mirror of https://github.com/crash-utility/crash
EPPIC extension support for crash-8.x + gdb-10.x
The previous version of the interface between eppic and crash/gdb was messy and not portable. This new version uses a clean interface with execution through the standard gnu_request and gdb command funnel. Signed-off-by: Luc Chouinard <lucchouina@gmail.com>
This commit is contained in:
parent
141e75f3c1
commit
2f1085df4d
20
defs.h
20
defs.h
|
@ -4768,6 +4768,23 @@ static inline unsigned int __const_hweight8(unsigned long w)
|
|||
|
||||
#endif /* !GDB_COMMON */
|
||||
|
||||
typedef enum drill_ops_s {
|
||||
EOP_MEMBER_SIZES,
|
||||
EOP_MEMBER_NAME,
|
||||
EOP_POINTER,
|
||||
EOP_TYPEDEF,
|
||||
EOP_INT,
|
||||
EOP_VALUE,
|
||||
EOP_ARRAY,
|
||||
EOP_UNION,
|
||||
EOP_ENUM,
|
||||
EOP_ENUMVAL,
|
||||
EOP_STRUCT,
|
||||
EOP_FUNCTION,
|
||||
EOP_DONE,
|
||||
EOP_OOPS
|
||||
} drill_ops_t;
|
||||
|
||||
/*
|
||||
* Common request structure for BFD or GDB data or commands.
|
||||
*/
|
||||
|
@ -4818,6 +4835,9 @@ struct gnu_request {
|
|||
char *member_target_type_name;
|
||||
char *member_target_type_tag_name;
|
||||
char *type_tag_name;
|
||||
/* callback function for 3rd party symbol and type (EPPIC for now) */
|
||||
void *priv;
|
||||
int (*tcb)(drill_ops_t, struct gnu_request *, const void *, const void *, const void *, const void *);
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -11,64 +11,68 @@
|
|||
|
||||
TARGET_FLAGS = -D$(TARGET)
|
||||
ifeq ($(TARGET), PPC64)
|
||||
TARGET_FLAGS += -m64
|
||||
TARGET_FLAGS += -m64
|
||||
endif
|
||||
ifeq ($(TARGET), ARM)
|
||||
TARGET_FLAGS += -m32
|
||||
TARGET_FLAGS += -m32
|
||||
endif
|
||||
ifeq ($(TARGET), MIPS)
|
||||
TARGET_FLAGS += -m32
|
||||
TARGET_FLAGS += -m32
|
||||
endif
|
||||
ifeq ($(TARGET), X86)
|
||||
TARGET_FLAGS += -m32
|
||||
TARGET_FLAGS += -m32
|
||||
endif
|
||||
|
||||
APPFILE=eppic/applications/crash/eppic.c
|
||||
GIT := $(shell which git 2> /dev/null)
|
||||
# crash 8 with gdb 10 uses new third party callback (tcb) API
|
||||
EPPIC_BRANCH=v5.0
|
||||
|
||||
all:
|
||||
@if [ -f /usr/bin/flex ] && [ -f /usr/bin/bison ]; then \
|
||||
if [ -f ../$(GDB)/crash.target ]; \
|
||||
then \
|
||||
if [ ! -f $(APPFILE) ]; \
|
||||
then \
|
||||
if [ -f "$(GIT)" ]; \
|
||||
then \
|
||||
if [ -n "$(EPPIC_GIT_URL)" ]; then \
|
||||
git clone $(EPPIC_GIT_OPTIONS) $(EPPIC_GIT_URL) eppic; \
|
||||
else \
|
||||
if ping -c 1 -W 5 github.com >/dev/null ; then \
|
||||
git clone $(EPPIC_GIT_OPTIONS) https://github.com/lucchouina/eppic.git eppic; \
|
||||
fi; \
|
||||
fi; \
|
||||
else \
|
||||
if [ ! -f "$(GIT)" ]; then \
|
||||
echo "eppic.so: git command is needed for pulling eppic extension code"; \
|
||||
fi; \
|
||||
fi; \
|
||||
fi; \
|
||||
if [ -f $(APPFILE) ]; \
|
||||
then \
|
||||
make -f eppic.mk eppic.so; \
|
||||
else \
|
||||
echo "eppic.so: failed to pull eppic code from git repo"; \
|
||||
fi; \
|
||||
else \
|
||||
echo "eppic.so: build failed: requires the crash $(GDB) module"; \
|
||||
fi ;\
|
||||
@if [ -f /usr/bin/flex ] && [ -f /usr/bin/bison ]; \
|
||||
then \
|
||||
if [ -f ../$(GDB)/crash.target ]; \
|
||||
then \
|
||||
if [ ! -f $(APPFILE) ]; \
|
||||
then \
|
||||
if [ -f "$(GIT)" ]; \
|
||||
then \
|
||||
if [ -n "$(EPPIC_GIT_URL)" ]; \
|
||||
then \
|
||||
git clone $(EPPIC_GIT_OPTIONS) $(EPPIC_GIT_URL) eppic; \
|
||||
else \
|
||||
if ping -c 1 -W 5 github.com >/dev/null ; then \
|
||||
git clone -b $(EPPIC_BRANCH) $(EPPIC_GIT_OPTIONS) https://github.com/lucchouina/eppic.git eppic; \
|
||||
fi; \
|
||||
fi; \
|
||||
else \
|
||||
if [ ! -f "$(GIT)" ]; then \
|
||||
echo "eppic.so: git command is needed for pulling eppic extension code"; \
|
||||
fi; \
|
||||
fi; \
|
||||
fi; \
|
||||
if [ -f $(APPFILE) ]; \
|
||||
then \
|
||||
make -f eppic.mk eppic.so; \
|
||||
else \
|
||||
echo "eppic.so: failed to pull eppic code from git repo"; \
|
||||
fi; \
|
||||
else \
|
||||
echo "eppic.so: build failed: requires the crash $(GDB) module"; \
|
||||
fi ;\
|
||||
else \
|
||||
echo "eppic.so: build failed: requires /usr/bin/flex and /usr/bin/bison"; \
|
||||
fi
|
||||
echo "eppic.so: build failed: requires /usr/bin/flex and /usr/bin/bison"; \
|
||||
fi
|
||||
|
||||
lib-eppic:
|
||||
cd eppic/libeppic && make
|
||||
|
||||
|
||||
eppic.so: ../defs.h $(APPFILE) lib-eppic
|
||||
gcc -g -Ieppic/libeppic -I../$(GDB)/gdb -I../$(GDB)/bfd -I../$(GDB)/include -I../$(GDB)/gdb/config -I../$(GDB)/gdb/common -I../$(GDB) -nostartfiles -shared -rdynamic -o eppic.so $(APPFILE) -fPIC $(TARGET_FLAGS) $(GDB_FLAGS) -Leppic/libeppic -leppic
|
||||
gcc -g -O0 -Ieppic/libeppic -I.. -nostartfiles -shared -rdynamic -o eppic.so $(APPFILE) -fPIC $(TARGET_FLAGS) $(GDB_FLAGS) -Leppic/libeppic -leppic
|
||||
|
||||
clean:
|
||||
if [ -d eppic/libeppic ]; \
|
||||
then \
|
||||
cd eppic/libeppic && make -i clean; \
|
||||
cd eppic/libeppic && make -i clean; \
|
||||
fi
|
||||
rm -f eppic.so
|
||||
|
|
302
gdb-10.2.patch
302
gdb-10.2.patch
|
@ -1737,3 +1737,305 @@ exit 0
|
|||
struct field *nextfield;
|
||||
short nfields;
|
||||
struct type *typedef_type, *target_type;
|
||||
--- gdb-10.2/gdb/symtab.c.orig
|
||||
+++ gdb-10.2/gdb/symtab.c
|
||||
@@ -6913,7 +6913,7 @@
|
||||
#include "../../defs.h"
|
||||
|
||||
static void get_member_data(struct gnu_request *, struct type *, long, int);
|
||||
-static void dump_enum(struct type *, struct gnu_request *);
|
||||
+static void walk_enum(struct type *, struct gnu_request *);
|
||||
static void eval_enum(struct type *, struct gnu_request *);
|
||||
static void gdb_get_line_number(struct gnu_request *);
|
||||
static void gdb_get_datatype(struct gnu_request *);
|
||||
@@ -7122,6 +7122,79 @@
|
||||
|
||||
|
||||
/*
|
||||
+ * Follow the type linkage for full member and value type resolution, with callback
|
||||
+ */
|
||||
+static void drillDownType(struct gnu_request *req, struct type *type)
|
||||
+{
|
||||
+ while (type)
|
||||
+ {
|
||||
+ /* check out for stub types and pull in the definition instead */
|
||||
+ if (TYPE_STUB(type) && TYPE_TAG_NAME(type)) {
|
||||
+ struct symbol *sym;
|
||||
+ sym = lookup_symbol(TYPE_TAG_NAME(type), 0, STRUCT_DOMAIN, 0).symbol;
|
||||
+ if (sym)
|
||||
+ type = sym->type;
|
||||
+ }
|
||||
+ switch (TYPE_CODE(type)) {
|
||||
+ drill_ops_t op;
|
||||
+ long l1, l2;
|
||||
+ int typecode;
|
||||
+
|
||||
+ case TYPE_CODE_PTR:
|
||||
+ req->tcb(EOP_POINTER, req, 0, 0, 0, 0);
|
||||
+ break;
|
||||
+
|
||||
+ case TYPE_CODE_TYPEDEF:
|
||||
+ req->is_typedef = 1;
|
||||
+ req->typecode = TYPE_CODE(type);
|
||||
+ if (!req->tcb(EOP_TYPEDEF, req, TYPE_NAME(type), 0, 0, 0))
|
||||
+ return;
|
||||
+ break;
|
||||
+
|
||||
+ case TYPE_CODE_FUNC:
|
||||
+ req->tcb(EOP_FUNCTION, req, 0, 0, 0, 0);
|
||||
+ break;
|
||||
+
|
||||
+ case TYPE_CODE_ARRAY:
|
||||
+ l1 = TYPE_LENGTH (type);
|
||||
+ l2 = TYPE_LENGTH (check_typedef(TYPE_TARGET_TYPE (type)));
|
||||
+ req->tcb(EOP_ARRAY, req, &l1, &l2, 0, 0);
|
||||
+ break;
|
||||
+
|
||||
+ case TYPE_CODE_VOID:
|
||||
+ case TYPE_CODE_INT:
|
||||
+ case TYPE_CODE_BOOL:
|
||||
+ l1 = TYPE_LENGTH(type);
|
||||
+ req->tcb(EOP_INT, req, &l1, 0, 0, 0);
|
||||
+ break;
|
||||
+
|
||||
+ case TYPE_CODE_UNION:
|
||||
+ op = EOP_UNION;
|
||||
+ goto label;
|
||||
+
|
||||
+ case TYPE_CODE_ENUM:
|
||||
+ op = EOP_ENUM;
|
||||
+ goto label;
|
||||
+
|
||||
+ case TYPE_CODE_STRUCT:
|
||||
+ op = EOP_STRUCT;
|
||||
+ goto label;
|
||||
+
|
||||
+ default:
|
||||
+ typecode = TYPE_CODE(type);
|
||||
+ req->tcb(EOP_OOPS, req, &typecode, "Unknown typecode", 0, 0);
|
||||
+ return; /* not reached */
|
||||
+
|
||||
+ label:
|
||||
+ l1 = TYPE_LENGTH(type);
|
||||
+ req->tcb(op, req, &l1, type, TYPE_TAG_NAME(type), 0);
|
||||
+ }
|
||||
+ type = TYPE_TARGET_TYPE(type);
|
||||
+ }
|
||||
+ req->tcb(EOP_DONE, req, 0, 0, 0, 0);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
* General purpose routine for determining datatypes.
|
||||
*/
|
||||
|
||||
@@ -7149,10 +7222,8 @@
|
||||
if (req->member)
|
||||
get_member_data(req, sym->type, 0, 1);
|
||||
|
||||
- if (TYPE_CODE(sym->type) == TYPE_CODE_ENUM) {
|
||||
- if (req->flags & GNU_PRINT_ENUMERATORS)
|
||||
- dump_enum(sym->type, req);
|
||||
- }
|
||||
+ if (TYPE_CODE(sym->type) == TYPE_CODE_ENUM)
|
||||
+ walk_enum(sym->type, req);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -7172,17 +7243,25 @@
|
||||
if (gdb_CRASHDEBUG(2))
|
||||
console("expr->elts[0].opcode: OP_VAR_VALUE\n");
|
||||
type = expr.get()->elts[2].symbol->type;
|
||||
- if (req->flags & GNU_VAR_LENGTH_TYPECODE) {
|
||||
+ if (req->tcb) {
|
||||
+ long value = SYMBOL_VALUE(expr->elts[2].symbol);
|
||||
+ /* callback with symbol value */
|
||||
req->typecode = TYPE_CODE(type);
|
||||
- req->length = TYPE_LENGTH(type);
|
||||
- }
|
||||
- if (TYPE_CODE(type) == TYPE_CODE_ENUM) {
|
||||
- req->typecode = TYPE_CODE(type);
|
||||
- req->value = SYMBOL_VALUE(expr.get()->elts[2].symbol);
|
||||
- req->tagname = (char *)TYPE_TAG_NAME(type);
|
||||
- if (!req->tagname) {
|
||||
- val = evaluate_type(expr.get());
|
||||
- eval_enum(value_type(val), req);
|
||||
+ req->tcb(EOP_VALUE, req, &value, 0, 0, 0);
|
||||
+ drillDownType(req, type);
|
||||
+ } else {
|
||||
+ if (req->flags & GNU_VAR_LENGTH_TYPECODE) {
|
||||
+ req->typecode = TYPE_CODE(type);
|
||||
+ req->length = TYPE_LENGTH(type);
|
||||
+ }
|
||||
+ if (TYPE_CODE(type) == TYPE_CODE_ENUM) {
|
||||
+ req->typecode = TYPE_CODE(type);
|
||||
+ req->value = SYMBOL_VALUE(expr->elts[2].symbol);
|
||||
+ req->tagname = (char *)TYPE_TAG_NAME(type);
|
||||
+ if (!req->tagname) {
|
||||
+ val = evaluate_type(expr.get());
|
||||
+ eval_enum(value_type(val), req);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -7192,26 +7271,21 @@
|
||||
console("expr->elts[0].opcode: OP_TYPE\n");
|
||||
type = expr.get()->elts[1].type;
|
||||
|
||||
- req->typecode = TYPE_CODE(type);
|
||||
- req->length = TYPE_LENGTH(type);
|
||||
-
|
||||
- if (TYPE_CODE(type) == TYPE_CODE_TYPEDEF) {
|
||||
- req->is_typedef = TYPE_CODE_TYPEDEF;
|
||||
- if ((typedef_type = check_typedef(type))) {
|
||||
- req->typecode = TYPE_CODE(typedef_type);
|
||||
- req->length = TYPE_LENGTH(typedef_type);
|
||||
- type = typedef_type;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (TYPE_CODE(type) == TYPE_CODE_ENUM) {
|
||||
- if (req->is_typedef)
|
||||
- if (req->flags & GNU_PRINT_ENUMERATORS) {
|
||||
- if (req->is_typedef)
|
||||
- fprintf_filtered(gdb_stdout,
|
||||
- "typedef ");
|
||||
- dump_enum(type, req);
|
||||
+ if (req->tcb) {
|
||||
+ drillDownType(req, type);
|
||||
+ } else {
|
||||
+ req->typecode = TYPE_CODE(type);
|
||||
+ req->length = TYPE_LENGTH(type);
|
||||
+ if (TYPE_CODE(type) == TYPE_CODE_TYPEDEF) {
|
||||
+ req->is_typedef = TYPE_CODE_TYPEDEF;
|
||||
+ if ((typedef_type = check_typedef(type))) {
|
||||
+ req->typecode = TYPE_CODE(typedef_type);
|
||||
+ req->length = TYPE_LENGTH(typedef_type);
|
||||
+ type = typedef_type;
|
||||
+ }
|
||||
}
|
||||
+ if (TYPE_CODE(type) == TYPE_CODE_ENUM)
|
||||
+ walk_enum(type, req);
|
||||
}
|
||||
|
||||
if (req->member)
|
||||
@@ -7233,36 +7307,38 @@
|
||||
* identifier, each on its own line.
|
||||
*/
|
||||
static void
|
||||
-dump_enum(struct type *type, struct gnu_request *req)
|
||||
+walk_enum(struct type *type, struct gnu_request *req)
|
||||
{
|
||||
int i;
|
||||
- int len;
|
||||
+ int len, print = (req->flags & GNU_PRINT_ENUMERATORS);
|
||||
long long lastval;
|
||||
|
||||
- len = TYPE_NFIELDS (type);
|
||||
- lastval = 0;
|
||||
- if (TYPE_TAG_NAME(type))
|
||||
- fprintf_filtered(gdb_stdout,
|
||||
- "enum %s {\n", TYPE_TAG_NAME (type));
|
||||
- else
|
||||
- fprintf_filtered(gdb_stdout, "enum {\n");
|
||||
+ if (print) {
|
||||
+ if (req->is_typedef)
|
||||
+ fprintf_filtered(gdb_stdout, "typedef ");
|
||||
+ if (TYPE_TAG_NAME(type))
|
||||
+ fprintf_filtered(gdb_stdout, "enum %s {\n", TYPE_TAG_NAME (type));
|
||||
+ else
|
||||
+ fprintf_filtered(gdb_stdout, "enum {\n");
|
||||
+ }
|
||||
|
||||
+ len = TYPE_NFIELDS (type);
|
||||
for (i = 0; i < len; i++) {
|
||||
- fprintf_filtered(gdb_stdout, " %s",
|
||||
- TYPE_FIELD_NAME (type, i));
|
||||
- if (lastval != TYPE_FIELD_ENUMVAL (type, i)) {
|
||||
- fprintf_filtered (gdb_stdout, " = %s",
|
||||
- plongest(TYPE_FIELD_ENUMVAL (type, i)));
|
||||
- lastval = TYPE_FIELD_ENUMVAL (type, i);
|
||||
- } else
|
||||
+ if (print)
|
||||
+ fprintf_filtered(gdb_stdout, " %s", TYPE_FIELD_NAME (type, i));
|
||||
+ lastval = TYPE_FIELD_ENUMVAL (type, i);
|
||||
+ if (print) {
|
||||
fprintf_filtered(gdb_stdout, " = %s", plongest(lastval));
|
||||
- fprintf_filtered(gdb_stdout, "\n");
|
||||
- lastval++;
|
||||
+ fprintf_filtered(gdb_stdout, "\n");
|
||||
+ } else if (req->tcb)
|
||||
+ req->tcb(EOP_ENUMVAL, req, TYPE_FIELD_NAME (type, i), &lastval, 0, 0);
|
||||
+ }
|
||||
+ if (print) {
|
||||
+ if (TYPE_TAG_NAME(type))
|
||||
+ fprintf_filtered(gdb_stdout, "};\n");
|
||||
+ else
|
||||
+ fprintf_filtered(gdb_stdout, "} %s;\n", req->name);
|
||||
}
|
||||
- if (TYPE_TAG_NAME(type))
|
||||
- fprintf_filtered(gdb_stdout, "};\n");
|
||||
- else
|
||||
- fprintf_filtered(gdb_stdout, "} %s;\n", req->name);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -7320,26 +7396,43 @@
|
||||
}
|
||||
|
||||
for (i = 0; i < nfields; i++) {
|
||||
- if (STREQ(req->member, nextfield->name)) {
|
||||
- req->member_offset = offset + nextfield->loc.bitpos;
|
||||
- req->member_length = TYPE_LENGTH(nextfield->type());
|
||||
- req->member_typecode = TYPE_CODE(nextfield->type());
|
||||
- req->member_main_type_name = (char *)TYPE_NAME(nextfield->type());
|
||||
- req->member_main_type_tag_name = (char *)TYPE_TAG_NAME(nextfield->type());
|
||||
- target_type = TYPE_TARGET_TYPE(nextfield->type());
|
||||
- if (target_type) {
|
||||
- req->member_target_type_name = (char *)TYPE_NAME(target_type);
|
||||
- req->member_target_type_tag_name = (char *)TYPE_TAG_NAME(target_type);
|
||||
- }
|
||||
- if ((req->member_typecode == TYPE_CODE_TYPEDEF) &&
|
||||
- (typedef_type = check_typedef(nextfield->type())))
|
||||
- req->member_length = TYPE_LENGTH(typedef_type);
|
||||
- return;
|
||||
- } else if (*nextfield->name == 0) { /* Anonymous struct/union */
|
||||
+ if (*nextfield->name == 0) { /* Anonymous struct/union */
|
||||
get_member_data(req, nextfield->type(),
|
||||
offset + nextfield->loc.bitpos, 0);
|
||||
if (req->member_offset != -1)
|
||||
return;
|
||||
+ } else {
|
||||
+ /* callback may be just looking for a specific member name */
|
||||
+ if (req->tcb) {
|
||||
+ if (req->tcb(EOP_MEMBER_NAME, req, nextfield->name, 0, 0, 0)) {
|
||||
+ long bitpos = FIELD_BITPOS(*nextfield);
|
||||
+ long bitsize = FIELD_BITSIZE(*nextfield);
|
||||
+ long len = TYPE_LENGTH(nextfield->type());
|
||||
+ long byteOffset;
|
||||
+ offset += nextfield->loc.bitpos;
|
||||
+ byteOffset = offset/8;
|
||||
+ console("EOP_MEMBER_SIZES\n");
|
||||
+ req->tcb(EOP_MEMBER_SIZES, req, &byteOffset, &len, &bitpos, &bitsize);
|
||||
+ /* callback with full type info */
|
||||
+ drillDownType(req, nextfield->type());
|
||||
+ }
|
||||
+ } else if (STREQ(req->member, nextfield->name)) {
|
||||
+ req->member_offset = offset + nextfield->loc.bitpos;
|
||||
+ req->member_length = TYPE_LENGTH(nextfield->type());
|
||||
+ req->member_typecode = TYPE_CODE(nextfield->type());
|
||||
+ req->member_main_type_name = (char *)TYPE_NAME(nextfield->type());
|
||||
+ req->member_main_type_tag_name = (char *)TYPE_TAG_NAME(nextfield->type());
|
||||
+ target_type = TYPE_TARGET_TYPE(nextfield->type());
|
||||
+ if (target_type) {
|
||||
+ req->member_target_type_name = (char *)TYPE_NAME(target_type);
|
||||
+ req->member_target_type_tag_name = (char *)TYPE_TAG_NAME(target_type);
|
||||
+ }
|
||||
+ if ((req->member_typecode == TYPE_CODE_TYPEDEF) &&
|
||||
+ (typedef_type = check_typedef(nextfield->type()))) {
|
||||
+ req->member_length = TYPE_LENGTH(typedef_type);
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
nextfield++;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue