From: Stefan Bader <stefan.bader@xxxxxxxxxxxxx> Date: Thu, 30 Aug 2012 11:28:28 +0900 Subject: [PATCH 13/16] [PATCH] Generic search into anonymous members in search_member(). There was a special case to find page.mapping in case it would be inside an anonymous union.struct. But recent kernel versions also moved page._count into the depths of some unnamed elements. Naturally not the same as page.mapping. So this tries to approach the problem by implementing a generic method of descending into anonymous sub-members. If this finds a member and it is the member offset that is the target of the search, that offset has to be adjusted on the way back out. Signed-off-by: Stefan Bader <stefan.bader at canonical.com> Signed-off-by: Atsushi Kumagai <kumagai-atsushi at mxc.nes.nec.co.jp> --- dwarf_info.c | 122 +++++++++++++++++++------------------------------------- dwarf_info.h | 1 - makedumpfile.c | 8 ---- makedumpfile.h | 6 --- 4 files changed, 42 insertions(+), 95 deletions(-) diff --git a/dwarf_info.c b/dwarf_info.c index 1429858..fb11e49 100644 --- a/dwarf_info.c +++ b/dwarf_info.c @@ -64,7 +64,6 @@ is_search_structure(int cmd) if ((cmd == DWARF_INFO_GET_STRUCT_SIZE) || (cmd == DWARF_INFO_GET_MEMBER_OFFSET) || (cmd == DWARF_INFO_GET_MEMBER_TYPE) - || (cmd == DWARF_INFO_GET_MEMBER_OFFSET_IN_UNION) || (cmd == DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION) || (cmd == DWARF_INFO_GET_MEMBER_ARRAY_LENGTH)) return TRUE; @@ -447,75 +446,41 @@ get_dwarf_base_type(Dwarf_Die *die) return TRUE; } -/* - * Function for searching struct page.union.struct.mapping. - */ static int -__search_mapping(Dwarf_Die *die, long *offset) +is_anonymous_container(Dwarf_Die *die) { - int tag; - const char *name; - Dwarf_Die child, *walker; - - if (dwarf_child(die, &child) != 0) + if (dwarf_diename(die)) return FALSE; - - walker = &child; - do { - tag = dwarf_tag(walker); - name = dwarf_diename(walker); - - if (tag != DW_TAG_member) - continue; - if ((!name) || strcmp(name, dwarf_info.member_name)) - continue; - if (!get_data_member_location(walker, offset)) - continue; + if (dwarf_tag(die) == DW_TAG_structure_type) + return TRUE; + if (dwarf_info.cmd != DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION + && dwarf_tag(die) == DW_TAG_union_type) return TRUE; - - } while (!dwarf_siblingof(walker, walker)); - return FALSE; } -/* - * Function for searching struct page.union.struct. - */ -static int -search_mapping(Dwarf_Die *die, long *offset) +static void +adjust_member_offset(Dwarf_Die *die) { - Dwarf_Die child, *walker; - Dwarf_Die die_struct; - - if (dwarf_child(die, &child) != 0) - return FALSE; - - walker = &child; - - do { - if (dwarf_tag(walker) != DW_TAG_member) - continue; - if (!get_die_type(walker, &die_struct)) - continue; - if (dwarf_tag(&die_struct) != DW_TAG_structure_type) - continue; - if (__search_mapping(&die_struct, offset)) - return TRUE; - } while (!dwarf_siblingof(walker, walker)); + long offset; - return FALSE; + if (dwarf_info.member_offset == NOT_FOUND_STRUCTURE) + return; + if (!get_data_member_location(die, &offset)) + return; + dwarf_info.member_offset += offset; } -static void +static int search_member(Dwarf_Die *die) { int tag; - long offset, offset_union; + long offset; const char *name; - Dwarf_Die child, *walker, die_union; + Dwarf_Die child, *walker, die_type; if (dwarf_child(die, &child) != 0) - return; + return FALSE; walker = &child; @@ -526,6 +491,20 @@ search_member(Dwarf_Die *die) if (tag != DW_TAG_member) continue; + /* + * Descend into anonymous members and search for member + * there. + */ + if (!name) { + if (!get_die_type(walker, &die_type)) + continue; + if (is_anonymous_container(&die_type)) + if (search_member(&die_type)) { + adjust_member_offset(walker); + return TRUE; + } + } + switch (dwarf_info.cmd) { case DWARF_INFO_GET_MEMBER_TYPE: if ((!name) || strcmp(name, dwarf_info.member_name)) @@ -535,39 +514,23 @@ search_member(Dwarf_Die *die) */ if (!get_dwarf_base_type(walker)) continue; - return; + return TRUE; case DWARF_INFO_GET_MEMBER_OFFSET: if ((!name) || strcmp(name, dwarf_info.member_name)) continue; /* * Get the member offset. */ - if (!get_data_member_location(walker, &offset)) + if (dwarf_tag(die) == DW_TAG_union_type) + offset = 0; + else if (!get_data_member_location(walker, &offset)) continue; dwarf_info.member_offset = offset; - return; - case DWARF_INFO_GET_MEMBER_OFFSET_IN_UNION: - if (!get_die_type(walker, &die_union)) - continue; - if (dwarf_tag(&die_union) != DW_TAG_union_type) - continue; - /* - * Search page.mapping in union. - */ - if (!search_mapping(&die_union, &offset_union)) - continue; - - /* - * Get the member offset. - */ - if (!get_data_member_location(walker, &offset)) - continue; - dwarf_info.member_offset = offset + offset_union; - return; + return TRUE; case DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION: - if (!get_die_type(walker, &die_union)) + if (!get_die_type(walker, &die_type)) continue; - if (dwarf_tag(&die_union) != DW_TAG_union_type) + if (dwarf_tag(&die_type) != DW_TAG_union_type) continue; /* * Get the member offset. @@ -575,7 +538,7 @@ search_member(Dwarf_Die *die) if (!get_data_member_location(walker, &offset)) continue; dwarf_info.member_offset = offset; - return; + return TRUE; case DWARF_INFO_GET_MEMBER_ARRAY_LENGTH: if ((!name) || strcmp(name, dwarf_info.member_name)) continue; @@ -584,14 +547,14 @@ search_member(Dwarf_Die *die) */ if (!get_data_array_length(walker)) continue; - return; + return TRUE; } } while (!dwarf_siblingof(walker, walker)); /* * Return even if not found. */ - return; + return FALSE; } static void @@ -636,7 +599,6 @@ search_structure(Dwarf_Die *die, int *found) break; case DWARF_INFO_GET_MEMBER_TYPE: case DWARF_INFO_GET_MEMBER_OFFSET: - case DWARF_INFO_GET_MEMBER_OFFSET_IN_UNION: case DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION: case DWARF_INFO_GET_MEMBER_ARRAY_LENGTH: search_member(die); diff --git a/dwarf_info.h b/dwarf_info.h index 1e07484..8d0084d 100644 --- a/dwarf_info.h +++ b/dwarf_info.h @@ -37,7 +37,6 @@ enum { DWARF_INFO_GET_STRUCT_SIZE, DWARF_INFO_GET_MEMBER_OFFSET, - DWARF_INFO_GET_MEMBER_OFFSET_IN_UNION, DWARF_INFO_GET_MEMBER_OFFSET_1ST_UNION, DWARF_INFO_GET_MEMBER_ARRAY_LENGTH, DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH, diff --git a/makedumpfile.c b/makedumpfile.c index 208087e..0a43181 100644 --- a/makedumpfile.c +++ b/makedumpfile.c @@ -877,17 +877,9 @@ get_structure_info(void) SIZE_INIT(page, "page"); OFFSET_INIT(page.flags, "page", "flags"); OFFSET_INIT(page._count, "page", "_count"); - OFFSET_INIT(page.mapping, "page", "mapping"); /* - * On linux-2.6.16 or later, page.mapping is defined - * in anonymous union. - */ - if (OFFSET(page.mapping) == NOT_FOUND_STRUCTURE) - OFFSET_IN_UNION_INIT(page.mapping, "page", "mapping"); - - /* * Some vmlinux(s) don't have debugging information about * page.mapping. Then, makedumpfile assumes that there is * "mapping" next to "private(unsigned long)" in the first diff --git a/makedumpfile.h b/makedumpfile.h index 4d6cbbb..7f5e1c6 100644 --- a/makedumpfile.h +++ b/makedumpfile.h @@ -244,12 +244,6 @@ do { \ == FAILED_DWARFINFO) \ return FALSE; \ } while (0) -#define OFFSET_IN_UNION_INIT(X, Y, Z) \ -do { \ - if ((OFFSET(X) = get_member_offset(Y, Z, DWARF_INFO_GET_MEMBER_OFFSET_IN_UNION)) \ - == FAILED_DWARFINFO) \ - return FALSE; \ -} while (0) #define SYMBOL_ARRAY_LENGTH_INIT(X, Y) \ do { \ if ((ARRAY_LENGTH(X) = get_array_length(Y, NULL, DWARF_INFO_GET_SYMBOL_ARRAY_LENGTH)) == FAILED_DWARFINFO) \ -- 1.7.9.2