Please find attached.
Thanks for the offline reviews Kazu and Lianbo!
Date: Fri, 9 Dec 2022 11:19:17 -0800 Subject: [PATCH] EPPIC extension support for crach_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@xxxxxxxxx> --- defs.h | 20 +++ extensions/eppic.mk | 80 ++++++------ gdb-10.2.patch | 303 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 365 insertions(+), 38 deletions(-) diff --git a/defs.h b/defs.h index afdcf6c..681bf2e 100644 --- a/defs.h +++ b/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 *); }; /* diff --git a/extensions/eppic.mk b/extensions/eppic.mk index b9c046b..8c0d70e 100644 --- a/extensions/eppic.mk +++ b/extensions/eppic.mk @@ -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 diff --git a/gdb-10.2.patch b/gdb-10.2.patch index 91edfb3..1fb7079 100644 --- a/gdb-10.2.patch +++ b/gdb-10.2.patch @@ -1737,3 +1737,306 @@ 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++; + } -- 2.25.1
-- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://listman.redhat.com/mailman/listinfo/crash-utility Contribution Guidelines: https://github.com/crash-utility/crash/wiki