commit f701ecad0f4b8d54b80455774b3ce4e328725a1b
Author: Dave Anderson <anderson@redhat.com>
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 <sys/ptrace.h>
#include <asm/types.h>
#include <sys/procfs.h>
+--- 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 <anderson@redhat.com>
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;