commit f701ecad0f4b8d54b80455774b3ce4e328725a1b Author: Dave Anderson Date: Wed Nov 7 12:02:51 2018 -0500 Implemented the functionality for a new MEMBER_TYPE_NAME() macro, which will return a pointer to the type name string of a structure member. It is being put in place for the support of Linux 4.20 radix tree to xarray replacements, where structure member types may be changed from radix_tree_root structures to xarray structures. (anderson@redhat.com) diff --git a/defs.h b/defs.h index bea70c5899ef..e8ade5778dd1 100644 --- a/defs.h +++ b/defs.h @@ -2232,6 +2232,7 @@ struct array_table { #define ANON_MEMBER_OFFSET_REQUEST ((struct datatype_member *)(-2)) #define MEMBER_TYPE_REQUEST ((struct datatype_member *)(-3)) #define STRUCT_SIZE_REQUEST ((struct datatype_member *)(-4)) +#define MEMBER_TYPE_NAME_REQUEST ((struct datatype_member *)(-5)) #define STRUCT_SIZE(X) datatype_info((X), NULL, STRUCT_SIZE_REQUEST) #define UNION_SIZE(X) datatype_info((X), NULL, STRUCT_SIZE_REQUEST) @@ -2241,6 +2242,7 @@ struct array_table { #define MEMBER_EXISTS(X,Y) (datatype_info((X), (Y), NULL) >= 0) #define MEMBER_SIZE(X,Y) datatype_info((X), (Y), MEMBER_SIZE_REQUEST) #define MEMBER_TYPE(X,Y) datatype_info((X), (Y), MEMBER_TYPE_REQUEST) +#define MEMBER_TYPE_NAME(X,Y) ((char *)datatype_info((X), (Y), MEMBER_TYPE_NAME_REQUEST)) #define ANON_MEMBER_OFFSET(X,Y) datatype_info((X), (Y), ANON_MEMBER_OFFSET_REQUEST) /* @@ -4546,6 +4548,10 @@ struct gnu_request { struct objfile *obj; } global_iterator; struct load_module *lm; + char *member_main_type_name; + char *member_main_type_tag_name; + char *member_target_type_name; + char *member_target_type_tag_name; }; /* diff --git a/gdb-7.6.patch b/gdb-7.6.patch index ec63c0df82b9..87447fa44094 100644 --- a/gdb-7.6.patch +++ b/gdb-7.6.patch @@ -2407,3 +2407,28 @@ diff -up gdb-7.6/opcodes/configure.orig gdb-7.6/opcodes/configure #include #include #include +--- gdb-7.6/gdb/symtab.c.orig ++++ gdb-7.6/gdb/symtab.c +@@ -5500,7 +5500,7 @@ get_member_data(struct gnu_request *req, + register short i; + struct field *nextfield; + short nfields; +- struct type *typedef_type; ++ struct type *typedef_type, *target_type; + + req->member_offset = -1; + +@@ -5523,6 +5523,13 @@ get_member_data(struct gnu_request *req, + 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); diff --git a/gdb_interface.c b/gdb_interface.c index 3cf99c1b6529..608da86058c2 100755 --- a/gdb_interface.c +++ b/gdb_interface.c @@ -512,6 +512,10 @@ dump_gnu_request(struct gnu_request *req, int in_gdb) console("member_offset: %ld\n", req->member_offset); console("member_length: %ld\n", req->member_length); console("member_typecode: %d\n", req->member_typecode); + console("member_main_type_name: %s\n", req->member_main_type_name); + console("member_main_type_tag_name: %s\n", req->member_main_type_tag_name); + console("member_target_type_name: %s\n", req->member_target_type_name); + console("member_target_type_tag_name: %s\n", req->member_target_type_tag_name); console("value: %lx ", req->value); console("tagname: \"%s\" ", req->tagname); console("pc: %lx ", req->pc); diff --git a/symbols.c b/symbols.c index 7966f129f80f..b1164613e342 100644 --- a/symbols.c +++ b/symbols.c @@ -5447,6 +5447,7 @@ datatype_init(void) * #define MEMBER_EXISTS(X,Y) (datatype_info((X), (Y), NULL) >= 0) * #define MEMBER_SIZE(X,Y) datatype_info((X), (Y), MEMBER_SIZE_REQUEST) * #define MEMBER_TYPE(X,Y) datatype_info((X), (Y), MEMBER_TYPE_REQUEST) + * #define MEMBER_TYPE_NAME(X,Y) datatype_info((X), (Y), MEMBER_TYPE_NAME_REQUEST) * #define ANON_MEMBER_OFFSET(X,Y) datatype_info((X), (Y), ANON_MEMBER_OFFSET_REQUEST) * * to determine structure or union sizes, or member offsets. @@ -5473,9 +5474,9 @@ datatype_info(char *name, char *member, struct datatype_member *dm) req->fp = pc->nullfp; gdb_interface(req); - if (req->flags & GNU_COMMAND_FAILED) { + if (req->flags & GNU_COMMAND_FAILED) { FREEBUF(req); - return -1; + return (dm == MEMBER_TYPE_NAME_REQUEST) ? 0 : -1; } if (!req->typecode) { @@ -5591,7 +5592,7 @@ datatype_info(char *name, char *member, struct datatype_member *dm) FREEBUF(req); if (dm && (dm != MEMBER_SIZE_REQUEST) && (dm != MEMBER_TYPE_REQUEST) && - (dm != STRUCT_SIZE_REQUEST)) { + (dm != STRUCT_SIZE_REQUEST) && (dm != MEMBER_TYPE_NAME_REQUEST)) { dm->type = type_found; dm->size = size; dm->member_size = member_size; @@ -5606,14 +5607,25 @@ datatype_info(char *name, char *member, struct datatype_member *dm) } } - if (!type_found) - return -1; + if (!type_found) + return (dm == MEMBER_TYPE_NAME_REQUEST) ? 0 : -1; if (dm == MEMBER_SIZE_REQUEST) return member_size; else if (dm == MEMBER_TYPE_REQUEST) return member_typecode; - else if (dm == STRUCT_SIZE_REQUEST) { + else if (dm == MEMBER_TYPE_NAME_REQUEST) { + if (req->member_main_type_name) + return (ulong)req->member_main_type_name; + else if (req->member_main_type_tag_name) + return (ulong)req->member_main_type_tag_name; + else if (req->member_target_type_name) + return (ulong)req->member_target_type_name; + else if (req->member_target_type_tag_name) + return (ulong)req->member_target_type_tag_name; + else + return 0; + } else if (dm == STRUCT_SIZE_REQUEST) { if ((req->typecode == TYPE_CODE_STRUCT) || (req->typecode == TYPE_CODE_UNION) || req->is_typedef) commit a812e59a175c8c6197ae3dc78bd5e1613adcc57c Author: Dave Anderson Date: Fri Aug 2 12:03:40 2019 -0400 Fix for the "timer" command in RHEL7.6 and later RHEL7 kernels. Without the patch, the command emits extra faulty timer entries because the tvec_root.vec[] and tvec.vec[] arrays are tracked using hlist_head structures where list_head structures should be used. (k-hagio@ab.jp.nec.com) diff --git a/kernel.c b/kernel.c index 3cd5bf1aab73..1ef063226041 100644 --- a/kernel.c +++ b/kernel.c @@ -53,7 +53,7 @@ static void dump_timer_data_timer_bases(const ulong *cpus); struct tv_range; static void init_tv_ranges(struct tv_range *, int, int, int); static int do_timer_list(ulong,int, ulong *, void *,ulong *,struct tv_range *); -static int do_timer_list_v3(ulong, int, ulong *, void *,ulong *); +static int do_timer_list_v3(ulong, int, ulong *, void *,ulong *, long); struct timer_bases_data; static int do_timer_list_v4(struct timer_bases_data *); static int compare_timer_data(const void *, const void *); @@ -8237,7 +8237,12 @@ dump_timer_data_tvec_bases_v3(const ulong *cpus) char buf3[BUFSIZE]; vec_root_size = vec_size = 0; - head_size = SIZE(hlist_head); + + if (STREQ(MEMBER_TYPE_NAME("tvec_root", "vec"), "list_head")) + /* for RHEL7.6 or later */ + head_size = SIZE(list_head); + else + head_size = SIZE(hlist_head); if ((i = get_array_length("tvec_root.vec", NULL, head_size))) vec_root_size = i; @@ -8275,15 +8280,15 @@ next_cpu: init_tv_ranges(tv, vec_root_size, vec_size, cpu); count += do_timer_list_v3(tv[1].base + OFFSET(tvec_root_s_vec), - vec_root_size, vec, NULL, NULL); + vec_root_size, vec, NULL, NULL, head_size); count += do_timer_list_v3(tv[2].base + OFFSET(tvec_s_vec), - vec_size, vec, NULL, NULL); + vec_size, vec, NULL, NULL, head_size); count += do_timer_list_v3(tv[3].base + OFFSET(tvec_s_vec), - vec_size, vec, NULL, NULL); + vec_size, vec, NULL, NULL, head_size); count += do_timer_list_v3(tv[4].base + OFFSET(tvec_s_vec), - vec_size, vec, NULL, NULL); + vec_size, vec, NULL, NULL, head_size); count += do_timer_list_v3(tv[5].base + OFFSET(tvec_s_vec), - vec_size, vec, NULL, NULL); + vec_size, vec, NULL, NULL, head_size); if (count) td = (struct timer_data *) @@ -8293,15 +8298,15 @@ next_cpu: get_symbol_data("jiffies", sizeof(ulong), &jiffies); do_timer_list_v3(tv[1].base + OFFSET(tvec_root_s_vec), - vec_root_size, vec, (void *)td, &highest); + vec_root_size, vec, (void *)td, &highest, head_size); do_timer_list_v3(tv[2].base + OFFSET(tvec_s_vec), - vec_size, vec, (void *)td, &highest); + vec_size, vec, (void *)td, &highest, head_size); do_timer_list_v3(tv[3].base + OFFSET(tvec_s_vec), - vec_size, vec, (void *)td, &highest); + vec_size, vec, (void *)td, &highest, head_size); do_timer_list_v3(tv[4].base + OFFSET(tvec_s_vec), - vec_size, vec, (void *)td, &highest); + vec_size, vec, (void *)td, &highest, head_size); tdx = do_timer_list_v3(tv[5].base + OFFSET(tvec_s_vec), - vec_size, vec, (void *)td, &highest); + vec_size, vec, (void *)td, &highest, head_size); qsort(td, tdx, sizeof(struct timer_data), compare_timer_data); @@ -8627,7 +8632,8 @@ do_timer_list_v3(ulong vec_kvaddr, int size, ulong *vec, void *option, - ulong *highest) + ulong *highest, + long head_size) { int i, t; int count, tdx; @@ -8645,19 +8651,24 @@ do_timer_list_v3(ulong vec_kvaddr, tdx++; } - readmem(vec_kvaddr, KVADDR, vec, SIZE(hlist_head) * size, + readmem(vec_kvaddr, KVADDR, vec, head_size * size, "timer_list vec array", FAULT_ON_ERROR); ld = &list_data; timer_list_buf = GETBUF(SIZE(timer_list)); - for (i = count = 0; i < size; i++, vec_kvaddr += SIZE(hlist_head)) { + for (i = count = 0; i < size; i++, vec_kvaddr += head_size) { - if (vec[i] == 0) - continue; + if (head_size == SIZE(list_head)) { + if (vec[i*2] == vec_kvaddr) + continue; + } else { + if (vec[i] == 0) + continue; + } BZERO(ld, sizeof(struct list_data)); - ld->start = vec[i]; + ld->start = (head_size == SIZE(list_head)) ? vec[i*2] : vec[i]; ld->list_head_offset = OFFSET(timer_list_entry); ld->end = vec_kvaddr; ld->flags = RETURN_ON_LIST_ERROR;