From: <cp...@sg...> - 2005-11-09 18:37:25
|
The dwarfextract.c code produces the tool that will extract dwarf debugging types from the kernel and kernel modules if they are compiled with -g. Signed-off-by: Cliff Wickman <cp...@sg...> --- This patch was submitted on 9/16 but was probably overlooked because of a nonstandard heading. Index: lkcd/7.X.X/lkcdutils/configure =================================================================== --- lkcd.orig/7.X.X/lkcdutils/configure 2004-12-21 15:26:00.000000000 -0800 +++ lkcd/7.X.X/lkcdutils/configure 2005-09-14 22:47:11.336487213 -0700 @@ -388,8 +388,11 @@ cd dwarf patch -p1 < ../PATCHES/dwarf-rela.patch patch -p1 < ../PATCHES/dwarf-lkcd.patch + patch -p1 < ../PATCHES/dwarf-dwarfextract.patch cd libdwarf ./configure + cd ../dwarfdump + ./configure cd ../.. # Add the pointer to the libdwarf directory so that we Index: lkcd/7.X.X/lkcdutils/PATCHES/dwarf-dwarfextract.patch =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ lkcd/7.X.X/lkcdutils/PATCHES/dwarf-dwarfextract.patch 2005-09-14 22:07:11.270144273 -0700 @@ -0,0 +1,6680 @@ +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ dwarf-dwarfextract/dwarfdump/dwarfextract.c 2005-09-14 21:30:58.715447923 -0700 +@@ -0,0 +1,6651 @@ ++/* ++ * This file is the source for a tool that will extract types (structures, ++ * typedefs, etc.) from a kernel or other binary that has been compiled ++ * with debugging information. ++ * ++ * Created by Silicon Graphics, Inc. ++ * ++ * Copyright (C) 2005 Silicon Graphics, Inc. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ */ ++/* ++ * dwarfextract ++ * ++ * Extracts the types out of a -g binary (esp. a DEBUG_INFO=y kernel). ++ * These types can be used by lcrash as its -t or --types ("kerntypes") file. ++ * ++ * usage: dwarfextract debugkernel kerntypes ++ * ++ * Based on dwarfdump ++ * cwickman 5/2005 ++ * ++ * Building this program: ++ * Build it like you would build dwarfdump. Place this source in the same ++ * directory as dwarfdump.c (dwarf/dwarfdump/) (tho' it does not depend on ++ * any parts of dwarfdump, but depends on some of the same header files). ++ * The dwarfdump/ directory sits next to the libdwarf/ directory. ++ * ++ * gcc -g -O2 -I. -I./../libdwarf -o dwarfextract dwarfextract.c ++ * -L../libdwarf -ldwarf -lelf ++ * ++ * note (6/2005): lcrash depends upon some structures in the kerntypes ++ * file that may not be in the kernel (they may be, if you grab all modules). ++ * If you don't extract from the modules you should do a ++ * "dwarfextract alltypes -c Kerntypes" to add the missing ones from the ++ * standard Kerntypes file. ++ * ++ * note: (8/2005) ++ * for lcrash's benefit, we could create typedef something like this: ++ * __linux_compile_version_id__uran_Sat_Jul_23_02_20_49_UTC_2005_t ++ * to identify the version of types file we are creating. ++ * (else it will complain "types: No version info found!") ++ * ++ * note: (9/2005) ++ * a very big -C file has been known to cause a SEGV in realloc() (when ++ * a malloc'd area being enlarged was initially very big). ++ * (e.g. INITIAL_NEEDPOINTERS of 35000 caused the failure when it was ++ * exceeded.) ++ * The reason for the failure is still unknown, but the problem went away ++ * when the initial size guesses were set higher or lower. ++ * ++ * note: (9/2005) ++ * extraction from a kernel alone took about 90 seconds ++ * extraction from a community kernel and 55 modules took about 5 minutes ++ * extraction from the 2.6 kernel and 1079 modules (sles9) took 2 hours! ++ */ ++#include "globals.h" /* includes libelf.h */ ++#include <sys/types.h> ++#include <fcntl.h> ++#include <getopt.h> ++#include <libdwarf.h> ++/* these for opaque: */ ++#include <dwarf_base_types.h> ++#include <dwarf_alloc.h> ++#include <dwarf_opaque.h> ++ ++#include <stdio.h> ++#include <errno.h> ++#include <malloc.h> ++#include <string.h> ++#include <sys/time.h> ++#include <bfd.h> ++#include <assert.h> ++#include <stdlib.h> ++#include <stddef.h> ++#define BUFSIZE 1024 ++#define NUM_SECTIONS 5 ++#if __WORDSIZE == 32 ++#define ELF_HEADER Elf32_Ehdr ++#define SECTION_HEADER Elf32_Shdr ++#else ++#define ELF_HEADER Elf64_Ehdr ++#define SECTION_HEADER Elf64_Shdr ++#endif ++#define SECTION_DEBUGABBREV 1 ++#define SECTION_DEBUGINFO 2 ++#define SECTION_RELDEBUGINFO 3 ++#define SECTION_STRING 4 ++ ++/* assumed size of a pointer - this is just used for attribute storage size, ++ so it works fine on 32-bit as well */ ++#define PTRSIZE 8 ++/* number of files allowed with -c; could be raised to any size but the max. ++ size of a command line is a practical limit; use -C for long lists */ ++#define NUMCFILES 255 ++/* make space for a large number die references that need translating */ ++/* the below 5 are arbitrary, but set high so that an extract of all the ++ types in a 2.6 kernel + modules does not cause realloc warning messages */ ++/* might as well be set high, as the malloc will not actually consume pages ++ until they are used */ ++/* max number of dies referencing something else (will need a ref. attribute):*/ ++#define INITIAL_REFERENCE 170000 ++/* max number of pieces in a debugging section: */ ++#define INITIAL_PIECES 1000 ++/* max number of structure prototypes in a debugging section: */ ++#define INITIAL_STRUCTPROTOS 130000 ++/* max number of dies that need pointers added to them: */ ++#define INITIAL_NEEDPOINTERS 75000 ++/* max number of dies that need array links added to them: */ ++#define INITIAL_NEEDARRAYS 10000 ++ ++#define FMAX 10000 /* max. number of files to concatenate */ ++#define LNOTFOUND 0 ++#define LFOUND 1 ++#define LUNPTR 2 ++#define LUNARRAY 3 ++#define PTRLINK 1 ++#define ARRAYLINK 2 ++extern int optind; ++extern char *optarg; ++/* the avl_ routines are copied from the GNU libavl */ ++/* libavl - library for manipulation of binary trees. ++ Copyright (C) 1998-2002 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or ++ modify it under the terms of the GNU General Public License as ++ published by the Free Software Foundation; either version 2 of the ++ License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ See the GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA ++ 02111-1307, USA. ++ ++ The author may be contacted at <bl...@gn...> on the Internet, or ++ write to Ben Pfaff, Stanford University, Computer Science Dept., 353 ++ Serra Mall, Stanford CA 94305, USA. ++*/ ++/* begin avl.h stuff */ ++typedef int avl_comparison_func (const void *avl_a, const void *avl_b, ++ void *avl_param); ++struct libavl_allocator ++{ ++ void *(*libavl_malloc) (struct libavl_allocator *, size_t libavl_size); ++ void (*libavl_free) (struct libavl_allocator *, void *libavl_block); ++}; ++void *avl_malloc (struct libavl_allocator *, size_t); ++void avl_free (struct libavl_allocator *, void *); ++struct libavl_allocator avl_allocator_default = { ++ avl_malloc, ++ avl_free ++}; ++#define AVL_MAX_HEIGHT 32 ++struct avl_table { ++ struct avl_node *avl_root; /* Tree's root. */ ++ avl_comparison_func *avl_compare; /* Comparison function. */ ++ void *avl_param; /* Extra argument to |avl_compare|. */ ++ struct libavl_allocator *avl_alloc; /* Memory allocator. */ ++ size_t avl_count; /* Number of items in tree. */ ++ unsigned long avl_generation; /* Generation number. */ ++}; ++struct avl_node { ++ struct avl_node *avl_link[2]; /* Subtrees. */ ++ void *avl_data; /* Pointer to data. */ ++ signed char avl_balance; /* Balance factor. */ ++}; ++struct avl_traverser { ++ struct avl_table *avl_table; /* Tree being traversed. */ ++ struct avl_node *avl_node; /* Current node in tree. */ ++ struct avl_node *avl_stack[AVL_MAX_HEIGHT]; ++ /* All the nodes above |avl_node|. */ ++ size_t avl_height; /* Number of nodes in |avl_parent|. */ ++ unsigned long avl_generation; /* Generation number. */ ++}; ++struct avl_table *avl_create (avl_comparison_func *, void *, ++ struct libavl_allocator *); ++void **avl_probe (struct avl_table *, void *); ++void *avl_insert (struct avl_table *, void *); ++void avl_t_init (struct avl_traverser *, struct avl_table *); ++void *avl_t_first (struct avl_traverser *, struct avl_table *); ++void *avl_t_next (struct avl_traverser *); ++void trav_refresh (struct avl_traverser *); ++/* end avl.h stuff */ ++int firstnewdie=1, verbose=0, debug=0, infd, outfd, tree_level; ++int start_count_level, member_hash_total, no_input_rel_debug_info_section=0; ++int out_string_size, file_debug_offset, in_place=0, tree_total=0; ++int num_cfiles=0, current_file_number=1, Hflag=0, Sflag=0; ++int num_refchecks, size_refchecks, aflag=0; ++int num_aliases=0, cflag=0, root_cus=0, sflag=0, gflag=0; ++int num_abbrev_pieces, num_debug_pieces, num_reldebug_pieces, Tflag=0; ++int size_abbrev_pieces, size_debug_pieces, size_reldebug_pieces; ++int total_dies=0, total_duplicates=0, total_cus=0, total_newdies=0; ++int tflag=0, pflag=0, total_structs=0, duplicate_structs=0, total_types=0; ++int reldebug_idx, debug_idx, abbrev_idx, string_idx, reldebug_strlen; ++int abbrev_size, debug_size, reldebug_size, total_unnamed_structs=0; ++int lookupcnt=0, addcnt=0, tree_branches, rflag=0, oflag=0, startsec; ++int tested_dies=0, deepest_nesting=0, num_refhash, Pflag=0; ++int num_protos, size_protos, num_needptrs, size_needptrs, scan_one_file=0; ++int num_needarrs, size_needarrs, *tree_namehashp, num_namehash; ++int is_32_bit=0, is_64_bit=0, needs_old; ++float lookuptime=0.0, addtime=0.0; ++char myno_die_name[] = "NO_NAME", *groupnamep; ++char *program_name, *in_file_name, *out_file_name, debug_buffer[BUFSIZE]; ++char indentation_string[100], indentation_spaces[100]; ++char reldebug_string[] = {".rel.debug_info\0"}; ++char **abbrev_addrp, **debug_addrp, **reldebug_addrp; ++char *in_string_buffer, *oname; ++char **cfilep, **struct_protonamep; ++Dwarf_Unsigned *abbrev_lengthp, *debug_lengthp, *reldebug_lengthp; ++/* Dwarf_Off is 8 bytes on both 32-bit and 64-bit Intel */ ++Dwarf_Off *struct_protop, *struct_protop2; ++Dwarf_Off *needptr_refp, *needptr_refp2, *needarr_refp, *needarr_refp2; ++Dwarf_Off *needarr_origp, *needarr_origp2, *tree_refhashp; ++ELF_HEADER inelfhdr, outelfhdr; ++SECTION_HEADER *base_shp, *debug_shp; ++Dwarf_Unsigned cu_offset = 0, producer_flags; ++Dwarf_Ptr producer_error; ++Dwarf_P_Die root_p_die, *ref_diep, *ref_diep2, void_pointer_die=0; ++Dwarf_P_Die common_base_type_die, *needptr_pdiep, *needarr_pdiep; ++Dwarf_P_Die *needptr_pdiep2, *needarr_pdiep2; ++Dwarf_Off *ref_refp, *ref_refp2; ++Dwarf_P_Debug newdbg; /* global, the new "Producer" dbg */ ++Dwarf_Debug *needarr_dbgp, *needarr_dbgp2; ++/* this is the type information of each unique type that we have ++ saved as a new Dwarf_P_Die */ ++struct typenode { ++ int members; ++ unsigned long long int hash; ++ int size; ++ int declaration; /* this is a structure declaration */ ++ Dwarf_Off tag; ++ char *namep; ++ /* the above 5 (combined) form the key to the node (sort order) */ ++ Dwarf_P_Die pdie; ++ Dwarf_P_Die ptrto; /* unnamed pointer case */ ++ Dwarf_P_Die arrto; /* unnamed array link case */ ++ Dwarf_Off offset; /* needed for a search by offset */ ++}; ++/* this is the type information of duplicates (already captured in the ++ typenode tree (tree_base)) */ ++struct aliasnode { ++ Dwarf_Off ref; /* sorted by this (offset+FMAX*file) */ ++ struct typenode *typep; /* the type that it is a duplicate of */ ++}; ++struct avl_table *tree_base, *alias_tree; ++struct typenode **alias_typep, **alias_typep2, ++ **needptr_typep, **needarr_typep, ++ **needptr_typep2, **needarr_typep2, ++ **tree_nametypep, **tree_reftypep; ++/* stuff from readelf binutils-<rlse>/binutils */ ++/* binutils-<rlse>/include/elf */ ++typedef struct elf_internal_rela { ++ bfd_vma r_offset; /* Location at which to apply the action */ ++ bfd_vma r_info; /* Index and Type of relocation */ ++ bfd_vma r_addend; /* Constant addend used to compute value */ ++} Elf_Internal_Rela; ++struct elf_internal_sym { /* Symbol table entry */ ++ bfd_vma st_value; /* Value of the symbol */ ++ bfd_vma st_size; /* Associated symbol size */ ++ unsigned long st_name; /* Symbol name, index in string tbl */ ++ unsigned char st_info; /* Type and binding attributes */ ++ unsigned char st_other; /* Visibilty, and target specific */ ++ unsigned int st_shndx; /* Associated section index */ ++}; ++typedef struct elf_internal_sym Elf_Internal_Sym; ++typedef struct { ++ unsigned long cu_length; ++ unsigned short cu_version; ++ unsigned long cu_abbrev_offset; ++ unsigned char cu_pointer_size; ++} DWARF2_Internal_CompUnit; ++typedef struct { ++ unsigned char r_offset[8]; /* Location at which to apply the ++ action */ ++ unsigned char r_info[8]; /* index and type of relocation */ ++ unsigned char r_addend[8]; /* Constant addend used to compute ++ value */ ++} Elf64_External_Rela; ++static bfd_vma (*byte_get) (unsigned char *, int); ++static void (*byte_put) (unsigned char *, bfd_vma, int); ++struct timeval tv; ++struct timezone tz; ++struct avl_traverser my_trav; ++/* If we can support a 64 bit data type then BFD64 should be defined ++ and sizeof (bfd_vma) == 8. In this case when translating from an ++ external 8 byte field to an internal field, we can assume that the ++ internal field is also 8 bytes wide and so we can extract all the data. ++ If, however, BFD64 is not defined, then we must assume that the ++ internal data structure only has 4 byte wide fields that are the ++ equivalent of the 8 byte wide external counterparts, and so we must ++ truncate the data. */ ++#ifdef BFD64 ++#define BYTE_GET8(field) byte_get (field, -8) ++#else ++#define BYTE_GET8(field) byte_get (field, 8) ++#endif ++/* end of readelf stuff */ ++ ++/* function prototypes */ ++int producer_callback(char *, int, Dwarf_Unsigned, ++ Dwarf_Unsigned, Dwarf_Unsigned, Dwarf_Unsigned, int *, int*); ++int process_one_file(Elf *, int); ++int is_type_we_want(Dwarf_Debug, Dwarf_Die, int *); ++int in_string_size; ++int decode_unsigned_leb128 (unsigned char *, int *); ++int get_offset(Dwarf_Debug, Dwarf_Attribute, Dwarf_Half); ++int is_a_struct(Dwarf_Die); ++int is_a_group(Dwarf_Die); ++int lookuptype(Dwarf_Debug, Dwarf_Die, struct avl_table *, int, ++ unsigned long long int, int, Dwarf_Half, char *, ++ struct typenode **, int *); ++int get_debug_sectionhead(int, SECTION_HEADER **, SECTION_HEADER **, ++ int, int, int, int); ++int file_is_relocatable(int); ++int process_concat_file(Elf *, char *, int, int); ++int child_count(Dwarf_Debug, Dwarf_Die); ++int has_attr_group(Dwarf_Debug, Dwarf_Die, Dwarf_Die *); ++int is_unnamed_pointer(Dwarf_Debug, Dwarf_Die, Dwarf_Half, char *); ++int is_unnamed_array(Dwarf_Debug, Dwarf_Die, Dwarf_Half, char *); ++int get_attr(Dwarf_Die, Dwarf_Half, Dwarf_Attribute *); ++int get_child(Dwarf_Die, Dwarf_Die *); ++int get_upper_bound(Dwarf_Attribute attr); ++int lookup_type_name(char *, struct typenode **); ++int lookup_type_ref(Dwarf_Off, struct typenode **); ++int lookup_needarr_ref(Dwarf_Off, int *, int *); ++int lookup_needptr_ref(Dwarf_Off, int *, int *); ++int lookup_reference_ref(Dwarf_Off, int *, int *); ++char *get_strings(int); ++char *get_strings_basic(int, SECTION_HEADER *, int); ++char *die_type (Dwarf_Die); ++char *name_of_die(Dwarf_Die); ++char *get_reftype(Dwarf_Die, Dwarf_Debug); ++struct typenode * inserttype(int, unsigned long long int, ++ int, Dwarf_Off, char *, Dwarf_P_Die, Dwarf_Off, int); ++void addtosavedtypes(char *, int, unsigned long long int, Dwarf_P_Die, ++ Dwarf_Die, int, Dwarf_Half, int); ++void print_a_die(Dwarf_Debug, Dwarf_Die); ++void test_a_die(Dwarf_Debug, Dwarf_Die); ++void walk_die_and_children(Dwarf_Debug, Dwarf_Die, Dwarf_P_Die); ++void display_die_and_children(Dwarf_Debug, Dwarf_Die ,Dwarf_P_Die); ++void walk_cus(Dwarf_Debug, int); ++void usage(); ++void init_refs_area(); ++void init_pieces_area(); ++void Cfilenames(char *); ++void get_options(int argc, char *argv[]); ++void setup_input_file(); ++void open_files (char *, char *); ++void add_to_trans_list(Dwarf_P_Die, Dwarf_Half); ++void do_reference_translations(); ++void addtoreflist(Dwarf_P_Die, Dwarf_Off); ++void trace_file(Elf *, int); ++void list_attributes(Dwarf_Debug, Dwarf_Die); ++void trace_input_elf_file(int, char *); ++void print_reference(Dwarf_Debug, Dwarf_Attribute, Dwarf_Half); ++void get_type_values(Dwarf_Debug, Dwarf_Die, char **, ++ unsigned long long int *, int *, int *, Dwarf_Half *, Dwarf_Off *, ++ int *); ++void save_abbrev_piece(char *, Dwarf_Unsigned); ++void save_debug_piece(char *, Dwarf_Unsigned); ++void save_reldebug_piece(char *, Dwarf_Unsigned); ++void producer_errhandler(Dwarf_Error, Dwarf_Ptr); ++void ref_summary(); ++void add_alias_tree(Dwarf_Die, struct typenode *, Dwarf_Off); ++void printTree(struct avl_table *); ++void concatenate (Elf *, int); ++void write_output_file(); ++void *get_data (void *, int, long, size_t); ++void byte_put_little_endian (unsigned char *, bfd_vma, int); ++void byte_put_big_endian (unsigned char *, bfd_vma, int); ++void read_elf_header(ELF_HEADER *, int); ++void test_endianness(ELF_HEADER *); ++void concatenate (Elf *, int); ++void show_structure(Dwarf_Debug, Dwarf_Die, char *, int, int); ++void show_die_offset(Dwarf_Debug, Dwarf_Die, int, int); ++void show_enum(Dwarf_Debug, Dwarf_Die, char *, int, int); ++void show_typedef(Dwarf_Debug, Dwarf_Die, char *, int, int); ++void show_union(Dwarf_Debug, Dwarf_Die, char *, int, int); ++void get_tag(Dwarf_Die, Dwarf_Half *); ++void add_to_needs_ptr_list(Dwarf_Off, Dwarf_P_Die); ++void add_to_needs_arr_list(Dwarf_Debug, Dwarf_Off, Dwarf_Off, Dwarf_P_Die); ++void add_to_proto_list(Dwarf_Off, Dwarf_Off, char *); ++void link_to_pointer(Dwarf_P_Die, Dwarf_P_Die); ++void get_refoffset(Dwarf_Attribute, Dwarf_Off *); ++void get_die(Dwarf_Debug, Dwarf_Off, Dwarf_Die *); ++void add_subranges(Dwarf_P_Die, Dwarf_Debug, Dwarf_Off); ++void sort_aliases(); ++void sort_references(); ++void make_types_name_ref_hash(); ++void walkTree_name_ref(struct avl_table *); ++void sort_treenames(); ++void sort_treerefs(); ++void sort_needptrs(); ++void sort_needarrs(); ++void init_misc_area(); ++void show_array(Dwarf_Debug, Dwarf_Die, char *, int , int); ++int my_params = 0; ++void printNodes(struct avl_node *, int); ++Dwarf_P_Die convert_to_new(Dwarf_Debug, Dwarf_P_Debug, Dwarf_Die, int); ++Dwarf_P_Die convert_subrange(Dwarf_Debug, Dwarf_P_Debug, Dwarf_Die); ++Dwarf_P_Die make_pointer_die(Dwarf_P_Die); ++Dwarf_P_Die make_array_die(Dwarf_P_Die); ++Dwarf_P_Die *alloc_pdie_list(int); ++Dwarf_Ptr _dwarf_p_get_alloc(Dwarf_P_Debug, Dwarf_Unsigned); ++Dwarf_Off current_offset(Dwarf_Die); ++Dwarf_Off *alloc_offset_list(int); ++Dwarf_Debug *alloc_dbg_list(int); ++struct typenode * NewtypeNode(int, unsigned long long int, int, Dwarf_Off, ++ char *, Dwarf_P_Die, Dwarf_Off, int); ++struct typenode **alloc_type_list(int); ++struct typenode *avl_find(struct avl_table *, void *); ++struct aliasnode *lookup_alias_ref(Dwarf_Off); ++Elf *open_as_elf(int, char *); ++int slurp_rela_relocs (int, unsigned long, unsigned long, ++ Elf_Internal_Rela **, unsigned long *); ++int typenode_compare(const void *, const void *, void *); ++int alias_compare(const void *, const void *, void *); ++bfd_vma byte_get_little_endian (unsigned char *, int); ++bfd_vma byte_get_big_endian (unsigned char *, int); ++int debug_apply_rela_addends(int, SECTION_HEADER *, SECTION_HEADER *, ++ int, unsigned char *, unsigned char *, unsigned char *, int, int); ++ ++int ++main(int argc, char *argv[]) ++{ ++ Elf *elf; ++ int i; ++ ++ for (i=0; i<100; i++) { ++ indentation_spaces[i]=' '; ++ } ++ indentation_spaces[99]='\0'; ++ (void) elf_version(EV_NONE); ++ if (elf_version(EV_CURRENT) == EV_NONE) { ++ (void) fprintf(stderr, "dwarfdump: libelf.a out of date.\n"); ++ exit(1); ++ } ++ ++ get_options(argc, argv); ++ ++ if (Pflag) { ++ gettimeofday(&tv, &tz); ++ startsec = tv.tv_sec; ++ } ++ open_files(in_file_name, out_file_name); ++ /*returns infd and (if not -t,-T,-a,-c) outfd, or exit*/ ++ ++ /* convert the open fd to an elf descriptor for some routines ++ below */ ++ ++ elf = open_as_elf(infd, in_file_name); ++ ++ if (scan_one_file) { ++ trace_input_elf_file(infd, in_file_name); ++ trace_file(elf, infd); ++ } else { ++ init_refs_area(); ++ init_misc_area(); ++ init_pieces_area(); ++ tree_base = avl_create (typenode_compare, &my_params, ++ &avl_allocator_default); ++ alias_tree = avl_create (alias_compare, &my_params, ++ &avl_allocator_default); ++ setup_input_file(); ++ ++ if (cflag) { ++ concatenate(elf, infd); ++ } else { ++ process_one_file(elf, infd); ++ } ++ } ++ ++ elf_end(elf); ++ close (infd); ++ ++ if (rflag) { ++ printf ("tested 0 dies; deepest nesting: 0\n", ++ tested_dies, deepest_nesting); ++ } ++ ++ if (tflag || Tflag || gflag || aflag || Hflag || Sflag || rflag || ++ oflag) { ++ exit(0); ++ } ++ ++ close (outfd); ++ if (Pflag) { ++ gettimeofday(&tv, &tz); ++ printf ("elapsed time: 0 seconds\n", tv.tv_sec-startsec); ++ } ++ exit(0); ++} ++ ++Elf * ++open_as_elf(int fd, char *file_name) ++{ ++ Elf_Cmd cmd; ++ Elf *elf; ++ Elf32_Ehdr *eh32; ++ Elf64_Ehdr *eh64; ++ ++ cmd = ELF_C_READ; ++ elf = elf_begin(fd, cmd, (Elf *) 0); ++ if (elf_kind(elf) == ELF_K_AR) { ++ printf (" is an archive; aborting\n", file_name); ++ exit(1); ++ } ++ ++ eh32 = elf32_getehdr(elf); ++ if (!eh32) { ++ /* not a 32-bit obj */ ++ /* must be a 62-bit obj */ ++ eh64 = elf64_getehdr(elf); ++ is_64_bit++; ++ if (!eh64) { ++ printf (" is neither 32 nor 64-bit\n", file_name); ++ exit(1); ++ } else { ++ if (debug) { ++ printf ("process the file \n", ++ file_name); ++ } ++ producer_flags = DW_DLC_SIZE_64; ++ } ++ } else { ++ is_32_bit++; ++ /* a 32-bit obj */ ++ if (debug) { ++ printf ("process the file \n", file_name); ++ } ++ producer_flags = DW_DLC_SIZE_32; ++ } ++ return elf; ++} ++ ++/* ++ * Given a file which we know is an elf file, process the dwarf data. ++ */ ++int ++process_one_file(Elf * elf, int fd) ++{ ++ int dres; ++ Dwarf_Debug dbg; ++ Dwarf_Error error; /* a structure */ ++ ++ dres = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &error); ++ if (dres == DW_DLV_NO_ENTRY) { ++ printf("No DWARF information present in \n", in_file_name); ++ return 0; ++ } ++ if (dres != DW_DLV_OK) { ++ printf ("dwarf_elf_init failed\n"); ++ exit(1); ++ } ++ ++ newdbg = dwarf_producer_init(producer_flags, producer_callback, ++ producer_errhandler, producer_error, &error); ++ if (newdbg < 0) { ++ printf ("dwarf_producer_init failed\n"); ++ exit(1); ++ } ++ if (debug) { ++ printf ("newdbg created at 0\n", newdbg); ++ } ++ ++ common_base_type_die = (Dwarf_P_Die)0; ++ /* ++ * Iterate through dwarf and extract all type info. ++ */ ++ if (debug) { ++ printf ("walking the CUs tree\n"); ++ } ++ walk_cus(dbg, fd); ++ if (pflag) { ++ printf ("0 types in tree\n", tree_base->avl_count); ++ } ++ if (debug) { ++ printf ("total new dies created 0\n", total_newdies); ++ } ++ ++ do_reference_translations(); ++ ++ dres = dwarf_finish(dbg, &error); ++ if (dres != DW_DLV_OK) { ++ printf ("dwarf_finish failed\n"); ++ exit(1); ++ } ++ ++ get_strings(1); /* get strings from input file and adjust */ ++ write_output_file(); ++ ++ if (!sflag) { ++ printf ("input file:\t\t\t\t\n", in_file_name); ++ printf ("compilation units:\t\t0\n", total_cus); ++ printf ("structures captured:\t\t0\n", total_structs); ++ printf ("output file:\t\t\t\t\n", out_file_name); ++ } ++ if (debug) { ++ printf ("final space usages:\n"); ++ printf ("num_refchecks: 0\n", num_refchecks); ++ printf ("num_aliases: 0\n", num_aliases); ++ printf ("num_debug_pieces: 0\n", num_debug_pieces); ++ } ++ return 0; ++} ++ ++/* ++ * Given a file which we know is an elf file, add its dwarf data to what ++ * we've already added to newdbg. ++ */ ++int ++process_concat_file(Elf * elf, char *filename, int fd, int filenumber) ++{ ++ int dres; ++ Dwarf_Debug concat_dbg; ++ Dwarf_Error error; /* a structure */ ++ ++ total_cus = total_dies = total_duplicates = ++ total_structs = total_unnamed_structs = duplicate_structs = 0; ++ ++ dres = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &concat_dbg, ++ &error); ++ if (dres == DW_DLV_NO_ENTRY) { ++ printf("No DWARF information present in \n", filename); ++ return 0; ++ } ++ if (dres != DW_DLV_OK) { ++ printf ("dwarf_elf_init failed\n"); ++ exit(1); ++ } ++ ++ if (!sflag) { ++ printf ("0/0, concatenating file \n", ++ filenumber+1, num_cfiles, filename); ++ } ++ ++ /* ++ * Iterate through dwarf and extract all type info. ++ */ ++ if (debug) { ++ printf ("walking the CUs tree for \n", filename); ++ } ++ walk_cus(concat_dbg, fd); ++ if (debug) { ++ printf ("total new dies created 0\n", total_newdies); ++ } ++ ++ if (needs_old == 0) { ++ /* leave the files open because we need the dbg ++ in place for needarr_dbgp use; unless this file ++ had none of them */ ++ dres = dwarf_finish(concat_dbg, &error); ++ } ++ ++ if (!sflag) { ++ printf (" compilation units:\t\t0\n", total_cus); ++ printf (" structures captured:\t\t0\n", total_structs); ++ printf (" types in tree:\t\t0\n", tree_base->avl_count); ++ } ++ return 0; ++} ++ ++void ++write_output_file() ++{ ++ int i, j, coffset, sh_size, string_offset; ++ int sh_offset, sections_offset; ++ int abbrev_offset, debug_offset, reldebug_offset; ++ Dwarf_Error error; ++ Dwarf_Signed numsections, section, elf_section_index; ++ Dwarf_Unsigned length; ++ Dwarf_Ptr gres; ++ SECTION_HEADER *shp1; ++ ++ /* write the new ELF header */ ++ /* coffset = lseek(outfd, 0, SEEK_CUR); */ ++ if ((i = write(outfd, &outelfhdr, sizeof(outelfhdr))) != ++ sizeof(outelfhdr)) { ++ printf ("cannot write elf header to ; abort\n", ++ in_place ? in_file_name : out_file_name); ++ exit(1); ++ } ++ ++ if (pflag) { ++ printf ("transforming to disk form and "); ++ printf("writing file \n", ++ in_place ? in_file_name : out_file_name); ++ } ++ numsections = dwarf_transform_to_disk_form (newdbg, &error); ++ if (numsections == DW_DLV_NOCOUNT) { ++ printf ("dwarf_transform_to_disk_form failed\n"); ++ exit(1); ++ } ++ ++ if (debug) { ++ printf ("transformed 0 disk image pieces\n", numsections); ++ } ++ gres = (Dwarf_Ptr)1; ++ section = 0; ++ while (gres) { ++ if (debug) { ++ printf ( ++ "calling dwarf_get_section_bytes for section 0\n", ++ section); ++ } ++ ++ gres = dwarf_get_section_bytes(newdbg, section, ++ &elf_section_index, &length, &error); ++ if (gres == NULL) { ++ if (debug) { ++ printf ( ++ "dwarf_get_section_bytes returned NULL at 0\n", ++ section); ++ } ++ if ((num_abbrev_pieces < 1) || ++ (num_debug_pieces < 1) || ++ (num_reldebug_pieces < 1)) { ++ printf ( ++ "did not get the expected 3 sections\n"); ++ exit(1); ++ } ++ } else { ++ /* we may get each section a piece at a time; we'll ++ have to save an array of starts and lengths */ ++ if (debug) { ++ printf ("dwarf_get_section_bytes index:0 ", ++ elf_section_index); ++ printf ("length:0\n", length); ++ } ++ if (elf_section_index == SECTION_DEBUGABBREV) { ++ save_abbrev_piece((char *)gres, length); ++ } else if (elf_section_index == SECTION_DEBUGINFO) { ++ save_debug_piece((char *)gres, length); ++ } else if (elf_section_index == SECTION_RELDEBUGINFO) { ++ save_reldebug_piece((char *)gres, length); ++ } else { ++ printf ( ++ "dwarf_get_section_bytes returned unexpected section number 0\n", ++ elf_section_index); ++ exit(1); ++ } ++ } ++ section++; ++ } ++ ++ /* future file location of section header table and sections */ ++ sh_offset = lseek(outfd, 0, SEEK_CUR); ++ sections_offset = sh_offset + (NUM_SECTIONS * sizeof(SECTION_HEADER)); ++ /* [1] (there is no [0] section, just [0] in section header table) */ ++ abbrev_offset = sections_offset; ++ /* [2] */ ++ debug_offset = abbrev_offset + abbrev_size; ++ /* [3] */ ++ reldebug_offset = debug_offset + debug_size; ++ /* [4] */ ++ string_offset = reldebug_offset + reldebug_size; ++ ++ /* build the section header table */ ++ ++ /* [0]: the required empty one */ ++ shp1 = &base_shp[0]; ++ shp1->sh_name = 0; ++ shp1->sh_type = 0; ++ shp1->sh_flags = 0; ++ shp1->sh_addr = 0; ++ shp1->sh_entsize = inelfhdr.e_shentsize; ++ shp1->sh_offset = 0; ++ shp1->sh_size = 0; ++ ++ /* [1]: the .debug_abbrev header */ ++ shp1 = &base_shp[SECTION_DEBUGABBREV]; ++ shp1->sh_name = abbrev_idx; ++ shp1->sh_offset = abbrev_offset; ++ shp1->sh_size = abbrev_size; ++ shp1->sh_type = 1; /* copy */ ++ shp1->sh_flags = 0; ++ shp1->sh_addr = 0; /* copy */ ++ shp1->sh_entsize = inelfhdr.e_shentsize; ++ ++ /* [2]: the .debug_info section */ ++ shp1 = &base_shp[SECTION_DEBUGINFO]; ++ shp1->sh_name = debug_idx; ++ shp1->sh_offset = debug_offset; ++ shp1->sh_size = debug_size; ++ shp1->sh_type = 1; /* copy */ ++ shp1->sh_flags = 0; ++ shp1->sh_addr = 0; /* copy */ ++ shp1->sh_entsize = inelfhdr.e_shentsize; ++ ++ /* [3]: the rel.debug_info section */ ++ shp1 = &base_shp[SECTION_RELDEBUGINFO]; ++ shp1->sh_name = reldebug_idx; ++ shp1->sh_offset = reldebug_offset; ++ shp1->sh_size = reldebug_size; ++ shp1->sh_type = 1; /* copy */ ++ shp1->sh_flags = 0; ++ shp1->sh_addr = 0; /* copy */ ++ shp1->sh_entsize = inelfhdr.e_shentsize; ++ ++ /* [4]: the strings section ++ /* size was already set to input file's string size ++ we just copy the one from the original input file */ ++ shp1 = &base_shp[SECTION_STRING]; ++ shp1->sh_name = string_idx; ++ shp1->sh_offset = string_offset; ++ shp1->sh_size = out_string_size; /* same strings as input file */ ++ /* elf_repl.h */ ++ shp1->sh_type = SHT_STRTAB; ++ shp1->sh_flags = 0; ++ shp1->sh_addr = 0; /* copy */ ++ shp1->sh_entsize = inelfhdr.e_shentsize; ++ ++ /* write the section header table */ ++ sh_size = NUM_SECTIONS * sizeof(SECTION_HEADER); ++ if (debug) { ++ coffset = lseek(outfd, 0, SEEK_CUR); ++ printf ("writing section header at 0 of (size 0)\n", ++ coffset, out_file_name, sh_size); ++ } ++ ++ if ((i = write(outfd, base_shp, sh_size)) != sh_size) { ++ printf ("cannot write section header table\n"); ++ exit(1); ++ } ++ ++ if (verbose) { ++ shp1 = base_shp; ++ printf ("output Section header table:\n"); ++ for (i=0; i<NUM_SECTIONS; i++, shp1++) { ++ printf (" section 0:\n", i); ++ printf (" sh_name:0 ()\n", shp1->sh_name, ++ in_string_buffer + shp1->sh_name); ++ printf (" sh_type:0\n", shp1->sh_type); ++ printf (" sh_flags:0\n", shp1->sh_flags); ++ printf (" sh_addr:0\n", shp1->sh_addr); ++ printf (" sh_offset:0\n", shp1->sh_offset); ++ printf (" sh_size:0\n", shp1->sh_size); ++ printf (" sh_entsize:0\n", shp1->sh_entsize); ++ } ++ } ++ ++ /* [1] write the abbrev section */ ++ if (debug) { ++ coffset = lseek(outfd, 0, SEEK_CUR); ++ printf ("writing abbrev section at 0 of (size 0)\n", ++ coffset, out_file_name, abbrev_size); ++ } ++ for (i=0; i<num_abbrev_pieces; i++) { ++ if ((j = write(outfd,*(abbrev_addrp+i), *(abbrev_lengthp+i))) != ++ *(abbrev_lengthp+i)) { ++ printf ("cannot write new abbrev section; abort\n"); ++ exit(1); ++ } ++ } ++ ++ /* [2] write the debug_info section */ ++ if (debug) { ++ coffset = lseek(outfd, 0, SEEK_CUR); ++ printf ("writing debug_info section at 0 of (size 0)\n", ++ coffset, out_file_name, debug_size); ++ } ++ for (i=0; i<num_debug_pieces; i++) { ++ if ((j = write(outfd, *(debug_addrp+i), *(debug_lengthp+i))) != ++ *(debug_lengthp+i)) { ++ printf ("cannot write new debug section; abort\n"); ++ exit(1); ++ } ++ } ++ ++ /* [3] write the rel.debug_info section */ ++ if (debug) { ++ coffset = lseek(outfd, 0, SEEK_CUR); ++ printf ( ++ "writing rel.debug_info section at 0 of (size 0)\n", ++ coffset, out_file_name, reldebug_size); ++ } ++ for (i=0; i<num_reldebug_pieces; i++) { ++ if ((j = write(outfd, *(reldebug_addrp+i), ++ *(reldebug_lengthp+i))) != *(reldebug_lengthp+i)) { ++ printf ("cannot write new reldebug section; abort\n"); ++ exit(1); ++ } ++ } ++ ++ /* [4] write the string section (just what we had on input) */ ++ if (debug) { ++ coffset = lseek(outfd, 0, SEEK_CUR); ++ printf ("writing string section at 0 of (size 0)\n", ++ coffset, out_file_name, out_string_size); ++ } ++ if ((i = write(outfd, in_string_buffer, out_string_size)) != ++ out_string_size) { ++ printf ("cannot write new string section; abort\n"); ++ exit(1); ++ } ++} ++ ++/* ++ * save the address and length of a piece of the abbrev section ++ */ ++void ++save_abbrev_piece(char *address, Dwarf_Unsigned length) ++{ ++ if (num_abbrev_pieces >= size_abbrev_pieces) { ++ num_abbrev_pieces = num_abbrev_pieces + (num_abbrev_pieces/2); ++ if (pflag) { ++ printf ("bump num_abbrev_pieces to 0 and realloc\n", ++ num_abbrev_pieces); ++ } ++ if ((abbrev_addrp = (char **)realloc((void *)abbrev_addrp, ++ num_abbrev_pieces * sizeof(char *))) == NULL) { ++ printf ("cannot realloc space for abbrev addrs\n"); ++ exit(1); ++ } ++ if ((abbrev_lengthp = ++ (Dwarf_Unsigned *)realloc((void *)abbrev_lengthp, ++ num_abbrev_pieces * sizeof(Dwarf_Unsigned))) == NULL) { ++ printf ("cannot realloc space for abbrev lenths\n"); ++ exit(1); ++ } ++ if (pflag) { ++ printf ("reallocs complete\n"); ++ } ++ } ++ ++ *(abbrev_addrp + num_abbrev_pieces) = address; ++ *(abbrev_lengthp + num_abbrev_pieces) = length; ++ abbrev_size += length; ++ num_abbrev_pieces++; ++ return; ++} ++ ++/* ++ * save the address and length of a piece of the debug section ++ */ ++void ++save_debug_piece(char *address, Dwarf_Unsigned length) ++{ ++ if (num_debug_pieces >= size_debug_pieces) { ++ size_debug_pieces = size_debug_pieces + (size_debug_pieces/2); ++ if (pflag) { ++ printf ("bump size_debug_pieces to 0 and realloc\n", ++ size_debug_pieces); ++ } ++ if ((debug_addrp = (char **)realloc((void *)debug_addrp, ++ size_debug_pieces * sizeof(char *))) == NULL) { ++ printf ("cannot realloc space for debug addrs\n"); ++ exit(1); ++ } ++ if ((debug_lengthp = ++ (Dwarf_Unsigned *)realloc((void *)debug_lengthp, ++ size_debug_pieces * sizeof(Dwarf_Unsigned))) == NULL) { ++ printf ("cannot realloc space for debug lengths\n"); ++ exit(1); ++ } ++ if (pflag) { ++ printf ("reallocs complete\n"); ++ } ++ } ++ ++ *(debug_addrp + num_debug_pieces) = address; ++ *(debug_lengthp + num_debug_pieces) = length; ++ debug_size += length; ++ num_debug_pieces++; ++ return; ++} ++ ++/* ++ * save the address and length of a piece of the debug section ++ */ ++void ++save_reldebug_piece(char *address, Dwarf_Unsigned length) ++{ ++ if (num_reldebug_pieces >= size_reldebug_pieces) { ++ size_reldebug_pieces = size_reldebug_pieces + ++ (size_reldebug_pieces/2); ++ if (pflag) { ++ printf ("bump size_reldebug_pieces to 0 and realloc\n", ++ size_reldebug_pieces); ++ ++ } ++ if ((reldebug_addrp = (char **)realloc((void *)reldebug_addrp, ++ size_reldebug_pieces * sizeof(char *))) == NULL) { ++ printf ("cannot realloc space for reldebug addrs\n"); ++ exit(1); ++ } ++ if ((reldebug_lengthp = ++ (Dwarf_Unsigned *)realloc((void *)reldebug_lengthp, ++ size_reldebug_pieces * sizeof(Dwarf_Unsigned))) ++ == NULL) { ++ printf ("cannot realloc space for reldebug lengths\n"); ++ exit(1); ++ } ++ if (pflag) { ++ printf ("reallocs complete\n"); ++ } ++ } ++ ++ *(reldebug_addrp + num_reldebug_pieces) = address; ++ *(reldebug_lengthp + num_reldebug_pieces) = length; ++ reldebug_size += length; ++ num_reldebug_pieces++; ++ return; ++} ++ ++/* ++ * save the address and length of a structure prototype ++ */ ++void ++add_to_proto_list(Dwarf_Off offset, Dwarf_Off offset2, char *namep) ++{ ++ char *cp; ++ ++ if (num_protos >= size_protos) { ++ size_protos = size_protos + (size_protos/2); ++ if (pflag) { ++ printf ("bump size_protos to 0 and realloc\n", ++ size_protos); ++ } ++ if ((struct_protop = (Dwarf_Off *) ++ realloc((void *)struct_protop, ++ size_protos * sizeof(Dwarf_Off))) == NULL) { ++ printf ("cannot realloc space for struct protos\n"); ++ exit(1); ++ } ++ if ((struct_protop2 = (Dwarf_Off *) ++ realloc((void *)struct_protop2, ++ size_protos * sizeof(Dwarf_Off))) == NULL) { ++ printf ("cannot realloc space for 2nd struct protos\n"); ++ exit(1); ++ } ++ if ((struct_protonamep = (char **) ++ realloc((void *)struct_protonamep, ++ size_protos * sizeof(char **))) == NULL) { ++ printf ("cannot realloc space for proto names\n"); ++ exit(1); ++ } ++ if (pflag) { ++ printf ("reallocs complete\n"); ++ } ++ } ++ ++ *(struct_protop + num_protos) = offset; /* offset within a dbg */ ++ *(struct_protop2 + num_protos) = offset2; /* offset within all files */ ++ if ((cp = (char *)malloc((int)strlen(namep)+1)) == NULL) { ++ printf ( "malloc of proto name failed\n"); ++ exit (1); ++ } ++ strcpy (cp, namep); ++ *(struct_protonamep + num_protos) = cp; ++ num_protos++; ++ return; ++} ++ ++/* ++ * process all DIE's in all compilation units ++ */ ++void ++walk_cus(Dwarf_Debug dbg, int fd) ++{ ++ int nres = DW_DLV_OK, sres, result; ++ unsigned char *end; ++ char *namep; ++ Dwarf_Unsigned cu_header_length = 0, abbrev_offset = 0; ++ Dwarf_Unsigned next_cu_offset = 0, dres; ++ Dwarf_Half version_stamp = 0, address_size = 0; ++ Dwarf_Die cu_die = 0, child; ++ Dwarf_Error error; /* pointer to a structure */ ++ Dwarf_P_Attribute aresult; ++ ++ /* Loop until there are no more Compilation Units */ ++ while ((nres = dwarf_next_cu_header(dbg, &cu_header_length, ++ &version_stamp, &abbrev_offset, &address_size, ++ &next_cu_offset, &error)) == DW_DLV_OK) { ++ total_cus++; ++ if (total_cus == 1) { ++ if (dbg->de_debug_info == NULL) { ++ printf ("de_debug_info is null; abort\n"); ++ exit(1); ++ } ++ if (file_is_relocatable(fd)) { ++ end = ++ dbg->de_debug_info+dbg->de_debug_info_size; ++ reloc_debug_info(dbg->de_debug_info, end, fd); ++ } ++ } ++ /*get "first" die of the CU (this is not a sibling)*/ ++ get_sibling(dbg, NULL, &cu_die); ++ if (debug) { ++ printf ("first CU die: 0 offset:0\n", ++ cu_die, current_offset(cu_die)); ++ } ++ /* convert the first CU to the root of our new tree */ ++ if (root_cus == 0) { ++ root_cus++; ++ root_p_die = convert_to_new(dbg, newdbg, cu_die, 0); ++ if (debug) { ++ printf ("created root_p_die\n"); ++ } ++ /* make this the root of the new graph */ ++ dres = dwarf_add_die_to_debug(newdbg, root_p_die, ++ &error); ++ if (dres != 0) { ++ printf ( ++ "dwarf_add_die_to_debug failed (0)\n",dres); ++ printf ("DW_DLV_NOCOUNT is 0\n", ++ DW_DLV_NOCOUNT); ++ exit(1); ++ } ++ if (debug) { ++ printf ("made new graph root\n"); ++ } ++ ++ /* add a producer attribute to the new root */ ++ aresult = dwarf_add_AT_producer(root_p_die, ++ program_name, &error); ++ if (aresult == (Dwarf_P_Attribute)DW_DLV_BADADDR) { ++ printf ("dwarf_add_AT_producer failed\n"); ++ exit(1); ++ } ++ } ++ if (pflag && current_file_number==1 && (total_cus % 10 == 0)) { ++ /* this progress item is only confusion for ++ a -c or -C file */ ++ printf ("CU: 0\n", total_cus); ++ } ++ ++ /* get the die of the CU */ ++ if (get_sibling(dbg, NULL, &cu_die)) { ++ /* start with the first child of cu_die; create ++ everything else that we select at the top level ++ of the CU as a sibling of this first child */ ++ if (get_child(cu_die, &child)) { ++ if (debug) { ++ printf ("walking children of \n", ++ name_of_die(cu_die)); ++ } ++ ++ tree_level = 0; ++ /* so that all the base types below the CU ++ begin at level 1 */ ++ if (debug) { ++ printf ( ++ "walk CUs die: 0 offset:0\n", ++ cu_die, current_offset(cu_die)); ++ } ++ walk_die_and_children(dbg, child, root_p_die); ++ ++ } ++ } ++ cu_offset = next_cu_offset; ++ if (debug) { ++ printf ("bump to next cu_offset\n"); ++ } ++ } ++ if (debug) { ++ printf ("end of all CUs\n"); ++ } ++} ++ ++/* ++ * recursively follow the die tree ++ */ ++void ++walk_die_and_children(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_P_Die parent_p_die) ++{ ++ int cdres, do_this_one, members, size, len; ++ int index, fndtype, alias_index, isptr, declaration; ++ unsigned long long int hash; ++ char *die_name, *namep, *stringp; ++ struct typenode *typep, *wtypep; ++ Dwarf_Error err; ++ Dwarf_Die child, sibling; ++ Dwarf_P_Die new_p_die; /* pointer to a producer structure */ ++ Dwarf_P_Die sibling_p_die; /* pointer to a producer structure */ ++ Dwarf_P_Die producer_p_die; ++ Dwarf_Half tag; ++ Dwarf_Off array_offset, typeoffset; /* of type pointed to */ ++ Dwarf_Attribute attr; ++ ++ if (debug) { ++ printf ("walk_die_and_children entered, tree_level:0 CU:0\n", ++ tree_level, total_cus); ++ } ++ /* if we don't create a p_die at this level, inherit the parent */ ++ new_p_die = parent_p_die; ++ tree_level++; /* becomes 1 on first entry of each CU */ ++ ++ while (die) { ++ ++ total_dies++; ++ if (pflag && current_file_number == 1) { ++ /* this progress item is only confusion for ++ a -c or -C file */ ++ if (total_dies % 100000 == 0) { ++ printf ( ++ "dies: 0 aliases:0 saved structures:0\n", ++ total_dies, num_aliases, total_structs); ++ } ++ } ++ do_this_one = is_type_we_want(dbg, die, &declaration); ++ if (debug) { ++ printf (": is_type_we_want:0\n", ++ name_of_die(die), do_this_one); ++ } ++ if (do_this_one) { ++ if (debug) { ++ printf ("begin die , offset 0 <0>\n", ++ name_of_die(die), current_offset(die), ++ current_offset(die)); ++ } ++ get_type_values(dbg, die, &namep, &hash, &members, ++ &size, &tag, &typeoffset, &isptr); ++ /* generally we only want structures at the highest ++ level, but within subprograms you find some down a ++ couple levels */ ++ if ((tree_level == 1) || ++ (tree_level < 5 && is_a_group(die))) { ++ /* duplicate elimination only for the highest ++ level */ ++ /* returns LNOTFOUND if this is a new (unique) ++ type */ ++ /* returns LFOUND if this is a normal found */ ++ /* returns LUNPTR if this is an unnamed pointer ++ to some other type */ ++ /* returns LUNARRAY if this is an unnamed array ++ link to some other type */ ++ fndtype = lookuptype(dbg, die, tree_base, ++ members, hash, size, tag, namep, &typep, ++ &alias_index); ++ } else { ++ fndtype = LNOTFOUND; ++ } ++ if (fndtype == LNOTFOUND) { ++ /* do this one, it is unique so far */ ++ /* (or it is a member of a wanted type) */ ++ if (is_a_struct(die)) { ++ total_structs++; ++ if (!strcmp(namep, myno_die_name)) { ++ total_unnamed_structs++; ++ } ++ } ++ /* leave do_this_one set */ ++ } else if (fndtype == LFOUND) { ++ /* this one is a duplicate */ ++ do_this_one = 0; ++ if (debug) { ++ printf ( ++ "duplicate: members:0 size:0 hash:0\n", ++ namep, members, size, hash); ++ } ++ /* add this to the alias - something may ++ refer to it and we will have to redirect ++ that reference to the thing it is a ++ duplicate of */ ++ add_alias_tree(die, typep, typeoffset); ++ total_duplicates++; ++ if (is_a_struct(die)) { ++ duplicate_structs++; ++ } ++ } else if (fndtype == LUNPTR) { ++ /* this is an unnamed pointer that ++ will be added to those types that reference ++ them (at the end of the program) */ ++ do_this_one = 0; ++ } else if (fndtype == LUNARRAY) { ++ /* this is an unnamed array link that ++ will be added to those types that reference ++ them (at the end of the program) */ ++ do_this_one = 0; ++ } ++ } ++ if (debug) { ++ printf (": after lookups, do this one:0\n", ++ name_of_die(die), do_this_one); ++ } ++ if (do_this_one) { ++ /* create a producer die for this and its selected ++ siblings ++ (unnamed pointers are not created until the very ++ end, when we know the dies that need them */ ++ new_p_die = convert_to_new(dbg, newdbg, die, isptr); ++ /* we need a new location for the name; the old ++ dbg may be thrown away before we're done, and ++ the name's address is recorded in the typenode */ ++ len = (int)strlen(namep); ++ stringp = (char *)malloc(len + 1); ++ strcpy(stringp, namep); ++ namep = stringp; ++ ++ if (isptr == PTRLINK) { ++ /* this die links to a pointer; add it to the ++ list of dies for which a pointer needs to ++ be created at the end */ ++ /* the pointer dies themselves are not ++ created yet (see LUNPTR) */ ++ add_to_needs_ptr_list(typeoffset, new_p_die); ++ } else if (isptr == ARRAYLINK) { ++ /* this is an array link; add it to the list ++ of dies for which an array link needs to ++ be created at the end */ ++ /* the array link dies themselves are not ++ created yet (see LUNARRAY) */ ++ if (!get_attr(die, DW_AT_type, &attr)) { ++ printf ("array link: no type\n"); ++ exit(1); ++ } ++ get_refoffset(attr, &array_offset); ++ add_to_needs_arr_list(dbg, array_offset, ++ typeoffset, new_p_die); ++ } ++ ++ /* this is a child; link it to its parent */ ++ ++ if (debug) { ++ printf ("link pdie 0 to parent 0\n", ++ new_p_die, parent_p_die); ++ } ++ producer_p_die = dwarf_die_link(new_p_die, ++ parent_p_die,NULL,NULL,NULL, &err); ++ if (producer_p_die == (Dwarf_P_Die)DW_DLV_BADADDR) { ++ printf ("first dwarf_die_link failed\n"); ++ exit(1); ++ } ++ /* Generally we just have structures and base types ++ at level 1; but exclude all the subroutines from ++ the duplicate-elimination tree. ++ Also take all the structures at higher levels. */ ++ if ((tree_level == 1 && tag != DW_TAG_subprogram) || ++ (tree_level < 5 && is_a_group(die))) { ++ addtosavedtypes(namep, members, hash, new_p_die, ++ die, size, tag, declaration); ++ if (debug) { ++ printf ("add to saved types\n", ++ namep); ++ } ++ } else { ++ if (debug) { ++ printf ( ++ " not added to saved types, level 0\n", ++ namep, tree_level); ++ } ++ } ++ } ++ ++ /* now do its children */ ++ if (do_this_one) { ++ /* do children before siblings: we are doing ++ depth-first walk */ ++ if (get_child(die, &child)) { ++ if (debug) { ++ printf ("walking children of \n", ++ name_of_die(die)); ++ } ++ walk_die_and_children(dbg, child, new_p_die); ++ } ++ } ++ ++ /* check whether there are any siblings to our current, ++ top level die */ ++ if (get_sibling(dbg, die, &sibling)) { ++ /* we do have a sibling, now in die "sibling" */ ++ die = sibling; ++ if (debug) { ++ printf ( ++ "found sibling \n", name_of_die(sibling)); ++ } ++ } else { ++ die = NULL; ++ if (debug) { ++ printf ("no more siblings\n"); ++ } ++ } ++ } ++ tree_level--; ++ return; ++} ++ ++void ++add_to_needs_ptr_list(Dwarf_Off typeoffset, Dwarf_P_Die pdie) ++{ ++ if (num_needptrs >= size_needptrs) { ++ size_needptrs = size_needptrs + (size_needptrs/2); ++ if (pflag) { ++ printf ("bump size_needptrs to 0 and realloc\n", ++ size_needptrs); ++ } ++ if ((needptr_refp = (Dwarf_Off *)realloc((void *)needptr_refp, ++ size_needptrs * sizeof(Dwarf_Off))) == NULL) { ++ printf ("cannot realloc space for needptr offsets\n"); ++ exit(1); ++ } ++ if ((needptr_typep = ++ (struct typenode **)realloc((void *)needptr_typep, ++ size_needptrs * sizeof(struct typenode *))) == NULL) { ++ printf ("cannot realloc space for needptr indices\n"); ++ exit(1); ++ } ++ if ((needptr_pdiep = ++ (Dwarf_P_Die *)realloc((void *)needptr_pdiep, ++ size_needptrs * sizeof(Dwarf_P_Die))) == NULL) { ++ printf ("cannot realloc space for needptr dies\n"); ++ exit(1); ++ } ++ if (pflag) { ++ printf ("reallocs complete\n"); ++ } ++ } ++ ++ *(needptr_refp + num_needptrs) = typeoffset*FMAX + ++ current_file_number; ++ *(needptr_pdiep + num_needptrs) = pdie; ++ *(needptr_typep + num_needptrs) = 0; ++ if (debug) { ++ printf ( ++ "adding offset 0 die 0 to need_pointer list, slot 0\n", ++ typeoffset, pdie, num_needptrs); ++ } ++ num_needptrs++; ++ return; ++} ++ ++void ++add_to_needs_arr_list(Dwarf_Debug dbg, Dwarf_Off this_offset, ++ Dwarf_Off typeoffset, Dwarf_P_Die pdie) ++{ ++ if (num_needarrs >= size_needarrs) { ++ size_needarrs = size_needarrs + (size_needarrs/2); ++ if (pflag) { ++ printf ("bump size_needarrs to 0 and realloc\n", ++ size_needarrs); ++ } ++ if ((needarr_refp = (Dwarf_Off *)realloc((void *)needarr_refp, ++ size_needarrs * sizeof(Dwarf_Off))) == NULL) { ++ printf ("cannot realloc space for needarr offsets\n"); ++ exit(1); ++ } ++ if ((needarr_typep = ++ (struct typenode **)realloc((void *)needarr_typep, ++ size_needarrs * sizeof(struct typenode *))) == NULL) { ++ printf ("cannot realloc space for needarr indices\n"); ++ exit(1); ++ } ++ if ((needarr_pdiep = ++ (Dwarf_P_Die *)realloc((void *)needarr_pdiep, ++ size_needarrs * sizeof(Dwarf_P_Die))) == NULL) { ++ printf ("cannot realloc space for needarr dies\n"); ++ exit(1); ++ } ++ if ((needarr_origp = (Dwarf_Off *)realloc((void *)needarr_origp, ++ size_needarrs * sizeof(Dwarf_Off))) == NULL) { ++ printf ("cannot realloc space for needarr origs\n"); ++ exit(1); ++ } ++ if ((needarr_dbgp = ++ (Dwarf_Debug *)realloc((void *)needarr_dbgp, ++ size_needarrs * sizeof(Dwarf_Debug))) == NULL) { ++ printf ("cannot realloc space for needarr dbgs\n"); ++ exit(1); ++ } ++ if (pflag) { ++ printf ("reallocs complete\n"); ++ } ++ } ++ ++ *(needarr_refp + num_needarrs) = typeoffset*FMAX + current_file_number; ++ *(needarr_pdiep + num_needarrs) = pdie; ++ *(needarr_typep + num_needarrs) = 0; ++ *(needarr_dbgp + num_needarrs) = dbg; ++ *(needarr_origp + num_needarrs) = this_offset; ++ if (debug) { ++ printf ( ++ "adding offset 0 die 0 to need_array list, slot 0\n", ++ typeoffset, pdie, num_needarrs); ++ } ++ needs_old++; /* remember to leave this file open */ ++ num_needarrs++; ++ return; ++} ++ ++/* ++ * return a die's name, or the NO_NAME string ++ */ ++char * ++name_of_die(Dwarf_Die die) ++{ ++ int result; ++ char *die_name; ++ Dwarf_Error err; ++ ++ result = dwarf_diename(die, &die_name, &err); ++ if (result == DW_DLV_ERROR) { ++ printf("die_name: dwarf_diename failed\n"); ++ exit(1); ++ } else if (result == DW_DLV_NO_ENTRY) { ++ return myno_die_name; ++ } else { ++ return die_name; ++ } ++} ++ ++/* ++ * print info about die (Debug Information Entry) ++ */ ++void ++print_a_die(Dwarf_Debug dbg, Dwarf_Die die) ++{ ++ int ores, result, members, size, pos, isptr; ++ unsigned long long int hash; ++ string tagname; ++ char *die_name; ++ Dwarf_Error err; ++ Dwarf_Signed i; ++ Dwarf_Off cuoffset, globaloffset; ++ Dwarf_Half dietag, tag; ++ Dwarf_Unsigned bytesize, bitsize; ++ ++ get_tag(die, &dietag); ++ ++ /* -o means display the members of something name <oname> */ ++ if (oflag) { ++ if (dietag == DW_TAG_structure_type || ++ dietag == DW_TAG_enumeration_type || ++ dietag == DW_TAG_typedef || ++ dietag == DW_TAG_union_type) { ++ die_name = name_of_die(die); ++ if (!strcmp(die_name, myno_die_name)) { ++ return; /* don't show unnamed items */ ++ } ++ if (!strcmp(die_name, oname)) { ++ if (dietag == DW_TAG_structure_type) { ++ show_structure(dbg, die, "", 0, 0); ++ } else if (dietag == DW_TAG_enumeration_type) { ++ show_enum(dbg, die, "", 0, 0); ++ } else if (dietag == DW_TAG_typedef) { ++ show_typedef(dbg, die, "", 0, 0); ++ } else if (dietag == DW_TAG_union_type) { ++ show_union(dbg, die, "", 0, 0); ++ } ++ } ++ } ++ return; ++ } ++ ++ /* -g means just display structures, unions, typedefs and enumerations*/ ++ if (gflag) { ++ if (dietag == DW_TAG_structure_type || ++ dietag == DW_TAG_enumeration_type || ++ dietag == DW_TAG_typedef || ++ dietag == DW_TAG_union_type) { ++ printf (" \n", die_type(die), name_of_die(die)); ++ } ++ return; ++ } ++ /* -a means display all types */ ++ if (aflag) { ++ printf ("\n", name_of_die(die)); ++ return; ++ } ++ /* -H means display just structures, with a hash total */ ++ if (Hflag) { ++ if (dietag != DW_TAG_structure_type) { ++ return; ++ } ++ die_name = name_of_die(die); ++ if (!strcmp(die_name, myno_die_name)) { ++ return; /* don't show unnamed items */ ++ } ++ get_type_values(dbg, die, &die_name, &hash, &members, ++ &size, &tag, &globaloffset, &isptr); ++ printf (" 0\n", die_name, hash); ++ return; ++ } ++ /* -S means display just structures, with their size */ ++ if (Sflag) { ++ if (dietag != DW_TAG_structure_type) { ++ return; ++ } ++ die_name = name_of_die(die); ++ if (!strcmp(die_name, myno_die_name)) { ++ return; /* don't show unnamed items */ ++ } ++ result = dwarf_bytesize(die, &bytesize, &err); ++ if (result == DW_DLV_ERROR) { ++ printf("print_a_die: problem reading byte size\n"); ++ exit(1); ++ } else if (result == DW_DLV_NO_ENTRY) { ++ bytesize = 0; ++ } ++ if (bytesize) { ++ printf (" 0\n", die_name, bytesize); ++ } else { ++ printf (" unknown-size\n", die_name); ++ } ++ return; ++ } ++ ++ strcpy(indentation_string, indentation_spaces); ++ indentation_string[(tree_level)*2] = '\0'; ++ printf ("", indentation_string); ++ ++ printf ("type: ", die_type(die)); ++ ++ die_name = name_of_die(die); ++ printf ("name: ", die_name); ++ ++ result = dwarf_bytesize(die, &bytesize, &err); ++ if (result == DW_DLV_ERROR) { ++ printf("print_a_die: problem reading byte size\n"); ++ exit(1); ++ } else if (result == DW_DLV_NO_ENTRY) { ++ bytesize = 0; ++ } ++ if (bytesize) { ++ printf ("bytesize:0 ", bytesize); ++ } ++ ++ result = dwarf_bitsize(die, &bitsize, &err); ++ if (result == DW_DLV_NO_ENTRY) { ++ bitsize = 0; ++ } else if (result == DW_DLV_ERROR) { ++ printf ("dwarf_bitsize failed\n"); ++ exit(1); ++ } ++ if (bitsize) { ++ printf ("bitsize:0 ", bitsize); ++ } ++ ++ get_tag(die, &tag); ++ globaloffset = current_offset(die); ++ ++ /* for cross-referencing, we'll use global offsets exclusively ++ ores = dwarf_die_CU_offset(die, &cuoffset, &err); ++ if (ores != DW_DLV_OK) { ++ printf ("dwarf_die_CU_offset failed\n"); ++ exit(1); ++ } ++ */ ++ ++ printf ("own_offset:0 ", globaloffset); ++ ++ if (!Tflag) { ++ get_type_values(dbg, die, &die_name, &hash, &members, ++ &size, &tag, &globaloffset, &isptr); ++ printf ("hash:0 members:0 ", hash, members); ++ printf ("\n"); ++ } ++ ++ list_attributes(dbg, die); ++ ++ return; ++} ++ ++char * ++die_type (Dwarf_Die die) ++{ ++ int result; ++ Dwarf_Half dietag; ++ ++ get_tag(die, &dietag); ++ switch(dietag) { ++ case DW_TAG_base_type:{ ++ return ("base type"); ++ } ++ case DW_TAG_enumeration_type: { ++ return ("enumeration "); ++ } ++ case DW_TAG_structure_type: { ++ return ("structure "); ++ } ++ case DW_TAG_union_type: { ++ return ("union "); ++ } ++ case DW_TAG_member: { ++ return ("member "); ++ } ++ case DW_TAG_typedef: { ++ return ("typedef "); ++ } ++ case DW_TAG_array_type: { ++ return ("array "); ++ } ++ case DW_TAG_pointer_type: { ++ return ("pointer "); ++ } ++ case DW_TAG_volatile_type: { ++ return ("volatile "); ++ } ++ case DW_TAG_const_type: { ++ return ("constant "); ++ } ++ case DW_TAG_subroutine_type: { ++ return ("subroutine "); ++ } ++ case DW_TAG_enumerator: { ++ return ("enumerator "); ++ } ++ case DW_TAG_formal_parameter: { ++ return ("paramater "); ++ } ++ case DW_TAG_subrange_type: { ++ return ("subrange "); ++ } ++ case DW_TAG_compile_unit: { ++ return ("compile unit "); ++ } ++ case DW_TAG_variable: { ++ return ("variable "); ++ } ++ case DW_TAG_subprogram: { ++ return ("subprogram "); ++ } ++ case DW_TAG_unspecified_parameters: { ++ return ("unspecified parameters "); ++ } ++ case DW_TAG_lexical_block: { ++ return ("lexical block "); ++ } ++ default: { ++ return (""); ++ } ++ } ++} ++ ++/* ++ * -o means display the members of a structure named <oname> ++ */ ++void ++show_structure(Dwarf_Debug dbg, Dwarf_Die die, char *name, int level, ++ int parent_offset) ++{ ++ int value; ++ char *die_name; ++ Dwarf_Die child_die, this_die, sibling_die; ++ Dwarf_Error err; ++ ++ die_name = name_of_die(die); ++ strcpy(indentation_string, indentation_spaces); ++ indentation_string[level*4] = '\0'; ++ printf ("", indentation_string); ++ printf (" \n", die_type(die), die_name, name); ++ level++; ++ ++ /* walk the children: */ ++ if (get_child(die, &child_die)) { ++ show_die_offset(dbg, child_die, level, parent_offset); ++ this_die = child_die; ++ while (get_sibling(dbg, this_die, &sibling_die)) { ++ show_die_offset(dbg, sibling_die, level, parent_offset); ++ this_die = sibling_die; ++ } ++ } ++ return; ++} ++ ++/* ++ * -o means display the members of a union named <oname> ++ */ ++void ++show_union(Dwarf_Debug dbg, Dwarf_Die die, char *name, int level, ++ int parent_offset) ++{ ++ int value; ++ char *die_name; ++ Dwarf_Die child_die, this_die, sibling_die; ++ Dwarf_Half tag; ++ Dwarf_Error err; ++ ++ die_name = name_of_die(die); ++ strcpy(indentation_string, indentation_spaces); ++ indentation_string[level*4] = '\0'; ++ printf ("", indentation_string); ++ printf (" \n", die_type(die), die_name, name); ++ level++; ++ ++ /* walk the children (overlapping members of this union) */ ++ if (get_child(die, &child_die)) { ++ die_name = name_of_die(child_die); ++ if (!strcmp(die_name, myno_die_name)) { ++ die_name = ""; ++ } ++ get_tag(child_die, &tag); ++ if (tag == DW_TAG_structure_type) { ++ show_structure(dbg, child_die, die_name, level, ++ parent_offset); ++ } else if (tag == DW_TAG_enumeration_type) { ++ show_enum(dbg, child_die, die_name, level, ++ parent_offset); ++ } else if (tag == DW_TAG_typedef) { ++ show_typedef(dbg, child_die, die_name, level, ++ parent_offset); ++ } else if (tag == DW_TAG_union_type) { ++ show_union(dbg, child_die, die_name, level, ++ parent_offset); ++ } else { ++ show_die_offset(dbg, child_die, level, parent_offset); ++ } ++ this_die = child_die; ++ while (get_sibling(dbg, this_die, &sibling_die)) { ++ show_die_offset(dbg, sibling_die, level, parent_offset); ++ this_die = sibling_die; ++ } ++ } ++ return; ++} ++ ++/* ++ * -o means display the members of a typedef named <oname> ++ */ ++void ++show_typedef(Dwarf_Debug dbg, Dwarf_Die die, char *name, int level, ++ int parent_offset) ++{ ++ int result, value, has_children=0; ++ char *die_name, *typedie_name; ++ Dwarf_Die child_die, this_die, sibling_die, type_die; ++ Dwarf_Error err; ++ ++ die_name = name_of_die(die); ++ if (has_attr_group(dbg, die, &type_die)) { ++ has_children++; ++ typedie_name = name_of_die(type_die); ++ if (!strcmp(typedie_name, myno_die_name)) { ++ typedie_name = ""; ++ } ++ } else { ++ typedie_name = ""; ++ } ++ strcpy(indentation_string, indentation_spaces); ++ indentation_string[level*4] = '\0'; ++ printf ("", indentation_string); ++ printf (" 0 0\n", ++ die_type(die), die_name, name, die_type(type_die), ++ typedie_name, parent_offset, parent_offset); ++ if (has_children) { ++ die = type_die; ++ level++; ++ ++ /* walk the children: */ ++ if (get_child(die, &child_die)) { ++ show_die_offset(dbg, child_die, level, parent_offset); ++ this_die = child_die; ++ while (... [truncated message content] |
From: Troy H. <tro...@hp...> - 2005-11-09 21:52:15
|
On 11/09/05 12:37, Cliff Wickman wrote: > > > The dwarfextract.c code produces the tool that will extract dwarf > debugging types from the kernel and kernel modules if they are > compiled with -g. Excellent. I have just checked it into the tree. Troy |