From fd2f003344354839663892f45f831a2dbfb71f17 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Thu, 28 Apr 2011 17:23:17 +0000 Subject: [PATCH] * NEWS: Add note about --dwarf-depth, --dwarf-start, and dwarf-mode.el. * objdump.c (suppress_bfd_header): New global. (usage): Update. (OPTION_DWARF_DEPTH, OPTION_DWARF_START): New constants. (options): Add dwarf-depth and dwarf-start entries. (dump_bfd): Use suppress_bfd_header. (main): Handle OPTION_DWARF_START, OPTION_DWARF_DEPTH. * doc/binutils.texi (objcopy): Document --dwarf-depth and --dwarf-start. (readelf): Likewise. * dwarf-mode.el: New file. * dwarf.c (dwarf_cutoff_level, dwarf_start_die): New globals. (read_and_display_attr_value): Also check debug_info_p. (process_debug_info): Handle dwarf_start_die and dwarf_cutoff_level. * dwarf.h (dwarf_cutoff_level, dwarf_start_die): Declare. * readelf.c (usage): Update. (OPTION_DWARF_DEPTH): New macro. (OPTION_DWARF_START): Likewise. (options): Add dwarf-depth and dwarf-start entries. (parse_args): Handle OPTION_DWARF_START and OPTION_DWARF_DEPTH. testsuite * binutils-all/objdump.W: Correct output. --- binutils/ChangeLog | 25 +++++ binutils/NEWS | 3 + binutils/doc/binutils.texi | 48 +++++++++ binutils/dwarf-mode.el | 167 ++++++++++++++++++++++++++++++ binutils/dwarf.c | 56 +++++++--- binutils/dwarf.h | 3 + binutils/objdump.c | 31 +++++- binutils/readelf.c | 23 ++++ binutils/testsuite/ChangeLog | 4 + binutils/testsuite/binutils-all/objdump.W | 2 +- 10 files changed, 344 insertions(+), 18 deletions(-) create mode 100644 binutils/dwarf-mode.el diff --git a/binutils/ChangeLog b/binutils/ChangeLog index da764cb..2cc6837 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,28 @@ +2011-04-28 Tom Tromey + + * NEWS: Add note about --dwarf-depth, --dwarf-start, and + dwarf-mode.el. + * objdump.c (suppress_bfd_header): New global. + (usage): Update. + (OPTION_DWARF_DEPTH, OPTION_DWARF_START): New constants. + (options): Add dwarf-depth and dwarf-start entries. + (dump_bfd): Use suppress_bfd_header. + (main): Handle OPTION_DWARF_START, OPTION_DWARF_DEPTH. + * doc/binutils.texi (objcopy): Document --dwarf-depth and + --dwarf-start. + (readelf): Likewise. + * dwarf-mode.el: New file. + * dwarf.c (dwarf_cutoff_level, dwarf_start_die): New globals. + (read_and_display_attr_value): Also check debug_info_p. + (process_debug_info): Handle dwarf_start_die and + dwarf_cutoff_level. + * dwarf.h (dwarf_cutoff_level, dwarf_start_die): Declare. + * readelf.c (usage): Update. + (OPTION_DWARF_DEPTH): New macro. + (OPTION_DWARF_START): Likewise. + (options): Add dwarf-depth and dwarf-start entries. + (parse_args): Handle OPTION_DWARF_START and OPTION_DWARF_DEPTH. + 2011-04-28 Jan Kratochvil * dwarf.c (display_gdb_index): Support version 5, warn on version 4. diff --git a/binutils/NEWS b/binutils/NEWS index d1b2a51..e069a25 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -3,6 +3,9 @@ * Add --preprocessor-arg option to windres to specify additional options passed to preprocessor. +* Add --dwarf-start and --dwarf-end to readelf and objdump. These are used by + the new Emacs mode, see dwarf-mode.el. + Changes in 2.21: * Add --interleave-width option to objcopy to allowing copying a range of diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 45a7ff7..08e1c4e 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -1076,6 +1076,8 @@ objcopy [@option{-F} @var{bfdname}|@option{--target=}@var{bfdname}] [@option{--subsystem=}@var{which}:@var{major}.@var{minor}] [@option{--compress-debug-sections}] [@option{--decompress-debug-sections}] + [@option{--dwarf-depth=@var{n}}] + [@option{--dwarf-start=@var{n}}] [@option{-v}|@option{--verbose}] [@option{-V}|@option{--version}] [@option{--help}] [@option{--info}] @@ -2129,6 +2131,28 @@ then only data found in those specific sections will be dumped. Note that there is no single letter option to display the content of trace sections or .gdb_index. +Note: the output from the @option{=info} option can also be affected +by the options @option{--dwarf-depth} and @option{--dwarf-start}. + +@item --dwarf-depth=@var{n} +Limit the dump of the @code{.debug_info} section to @var{n} children. +This is only useful with @option{--dwarf=info}. The default is +to print all DIEs; the special value 0 for @var{n} will also have this +effect. + +With a non-zero value for @var{n}, DIEs at or deeper than @var{n} +levels will not be printed. The range for @var{n} is zero-based. + +@item --dwarf-start=@var{n} +Print only DIEs beginning with the DIE numbered @var{n}. This is only +useful with @option{--dwarf=info}. + +If specified, this option will suppress printing of any header +information and all DIEs before the DIE numbered @var{n}. Only +siblings and children of the specified DIE will be printed. + +This can be used in conjunction with @option{--dwarf-depth}. + @item -G @itemx --stabs @cindex stab @@ -3957,6 +3981,8 @@ readelf [@option{-a}|@option{--all}] [@option{-c}|@option{--archive-index}] [@option{-w[lLiaprmfFsoRt]}| @option{--debug-dump}[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges,=pubtypes,=trace_info,=trace_abbrev,=trace_aranges,=gdb_index]] + [@option{--dwarf-depth=@var{n}}] + [@option{--dwarf-start=@var{n}}] [@option{-I}|@option{--histogram}] [@option{-v}|@option{--version}] [@option{-W}|@option{--wide}] @@ -4124,6 +4150,28 @@ Note: the @option{=frames-interp} option will display the interpreted contents of a .debug_frame section whereas the @option{=frames} option dumps the contents in a raw format. +Note: the output from the @option{=info} option can also be affected +by the options @option{--dwarf-depth} and @option{--dwarf-start}. + +@item --dwarf-depth=@var{n} +Limit the dump of the @code{.debug_info} section to @var{n} children. +This is only useful with @option{--debug-dump=info}. The default is +to print all DIEs; the special value 0 for @var{n} will also have this +effect. + +With a non-zero value for @var{n}, DIEs at or deeper than @var{n} +levels will not be printed. The range for @var{n} is zero-based. + +@item --dwarf-start=@var{n} +Print only DIEs beginning with the DIE numbered @var{n}. This is only +useful with @option{--debug-dump=info}. + +If specified, this option will suppress printing of any header +information and all DIEs before the DIE numbered @var{n}. Only +siblings and children of the specified DIE will be printed. + +This can be used in conjunction with @option{--dwarf-depth}. + @item -I @itemx --histogram Display a histogram of bucket list lengths when displaying the contents diff --git a/binutils/dwarf-mode.el b/binutils/dwarf-mode.el new file mode 100644 index 0000000..3362bc4 --- /dev/null +++ b/binutils/dwarf-mode.el @@ -0,0 +1,167 @@ +;;; dwarf-mode.el --- Browser for DWARF information. + +;; Version: 1.0 + +;; This file is not part of GNU Emacs, but is distributed under the +;; same terms: + +;; GNU Emacs 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 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs 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 GNU Emacs. If not, see . + +;;; Code: + +(defvar dwarf-objdump-program "objdump") + +(defconst dwarf-font-lock-keywords + '( + ;; Name and linkage name. + ("DW_AT_[a-z_]*name\\s *: .*:\\(.*\\)\\s *$" + (1 font-lock-function-name-face)) + + ("Compilation Unit @ offset 0x[0-9a-f]+" + (0 font-lock-string-face)) + )) + +(defvar dwarf-file nil + "Buffer-local variable holding the file name passed to objdump.") + +;; Expand a "..." to show all the child DIES. NEW-DEPTH controls how +;; deep to display the new dies; `nil' means display all of them. +(defun dwarf-do-insert-substructure (new-depth die) + (let ((inhibit-read-only t)) + (beginning-of-line) + (delete-region (point) (progn + (end-of-line) + (forward-char) + (point))) + (save-excursion + (apply #'call-process dwarf-objdump-program nil (current-buffer) nil + "-Wi" (concat "--dwarf-start=0x" die) + dwarf-file + (if new-depth (list (concat "--dwarf-depth=" + (int-to-string new-depth)))))) + (set-buffer-modified-p nil))) + +(defun dwarf-insert-substructure-button (die) + (beginning-of-line) + (unless (looking-at "^ <\\([0-9]+\\)>") + (error "Unrecognized line.")) + (let ((new-depth (1+ (string-to-int (match-string 1))))) + (dwarf-do-insert-substructure new-depth die))) + +(defun dwarf-insert-substructure (arg) + "Expand a `...' to show children of the current DIE. +By default, expands just one level of children. +A prefix argument means expand all children." + (interactive "P") + (beginning-of-line) + (unless (looking-at "^ <\\([0-9]+\\)><\\([0-9a-f]+\\)>") + (error "Unrecognized line.")) + (let ((die (match-string 2))) + (if arg + (dwarf-do-insert-substructure nil die) + (dwarf-insert-substructure-button die)))) + +;; Called when a button is pressed. +;; Either follows a DIE reference, or expands a "...". +(defun dwarf-die-button-action (button) + (let* ((die (button-get button 'die)) + ;; Note that the first number can only be decimal. + (die-rx (concat "^\\s *\\(<[0-9]+>\\)?<" + die ">[^<]")) + (old (point)) + (is-ref (button-get button 'die-ref))) + (if is-ref + (progn + (goto-char (point-min)) + (if (re-search-forward die-rx nil 'move) + (push-mark old) + (goto-char old) + (error "Could not find DIE <0x%s>" die))) + (dwarf-insert-substructure-button die)))) + +;; Button definition. +(define-button-type 'dwarf-die-button + 'follow-link t + 'action #'dwarf-die-button-action) + +;; Helper regexp to match a DIE reference. +(defconst dwarf-die-reference ": \\(<0x\\([0-9a-f]+\\)>\\)\\s *$") + +;; Helper regexp to match a `...' indicating that there are hidden +;; children. +(defconst dwarf-die-more "^ <[0-9]+><\\([0-9a-z]+\\)>: \\([.][.][.]\\)") + +;; jit-lock callback function to fontify a region. This applies the +;; buttons, since AFAICT there is no good way to apply buttons via +;; font-lock. +(defun dwarf-fontify-region (start end) + (save-excursion + (let ((beg-line (progn (goto-char start) (line-beginning-position))) + (end-line (progn (goto-char end) (line-end-position)))) + (goto-char beg-line) + (while (re-search-forward dwarf-die-reference end-line 'move) + (let ((b-start (match-beginning 1)) + (b-end (match-end 1)) + (hex (match-string-no-properties 2))) + (make-text-button b-start b-end :type 'dwarf-die-button + 'die hex 'die-ref t))) + ;; This is a bogus approach. Why can't we make buttons from the + ;; font-lock defaults? + (goto-char beg-line) + (while (re-search-forward dwarf-die-more end-line 'move) + (let ((hex (match-string-no-properties 1)) + (b-start (match-beginning 2)) + (b-end (match-end 2))) + (make-text-button b-start b-end :type 'dwarf-die-button + 'die hex 'die-ref nil)))))) + +;; Run objdump and insert the contents into the buffer. The arguments +;; are the way they are because this is also called as a +;; revert-buffer-function. +(defun dwarf-do-refresh (&rest ignore) + (let ((inhibit-read-only t)) + (erase-buffer) + (save-excursion + (call-process dwarf-objdump-program + nil (current-buffer) nil + "-Wi" "--dwarf-depth=1" + dwarf-file)) + (set-buffer-modified-p nil))) + +;;;###autoload +(define-derived-mode dwarf-mode special-mode "DWARF" + "Major mode for browsing DWARF output. + +\\{dwarf-mode-map}" + + (set (make-local-variable 'font-lock-defaults) '(dwarf-font-lock-keywords)) + ;; FIXME: we could be smarter and check the file time. + (set (make-local-variable 'revert-buffer-function) #'dwarf-do-refresh) + (jit-lock-register #'dwarf-fontify-region)) + +(define-key dwarf-mode-map [(control ?m)] #'dwarf-insert-substructure) + +;;:###autoload +(defun dwarf-browse (file) + "Invoke `objdump' and put output into a `dwarf-mode' buffer. +This is the main interface to `dwarf-mode'." + (interactive "fFile name: ") + (let* ((base-name (file-name-nondirectory file)) + (buffer (generate-new-buffer (concat "*DWARF for " base-name "*")))) + (pop-to-buffer buffer) + (dwarf-mode) + (set (make-local-variable 'dwarf-file) file) + (dwarf-do-refresh))) + +(provide 'dwarf-mode) diff --git a/binutils/dwarf.c b/binutils/dwarf.c index c37a1f3..d8e66a3 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -63,6 +63,9 @@ int do_trace_abbrevs; int do_trace_aranges; int do_wide; +int dwarf_cutoff_level = -1; +unsigned long dwarf_start_die; + /* Values for do_debug_lines. */ #define FLAG_DEBUG_LINES_RAW 1 #define FLAG_DEBUG_LINES_DECODED 2 @@ -1414,7 +1417,8 @@ read_and_display_attr_value (unsigned long attribute, } if ((do_loc || do_debug_loc || do_debug_ranges) - && num_debug_info_entries == 0) + && num_debug_info_entries == 0 + && debug_info_p != NULL) { switch (attribute) { @@ -2028,7 +2032,8 @@ process_debug_info (struct dwarf_section *section, if (!do_loc) { - printf (_("Contents of the %s section:\n\n"), section->name); + if (dwarf_start_die == 0) + printf (_("Contents of the %s section:\n\n"), section->name); load_debug_section (str, file); } @@ -2046,7 +2051,7 @@ process_debug_info (struct dwarf_section *section, DWARF2_Internal_CompUnit compunit; unsigned char *hdrptr; unsigned char *tags; - int level; + int level, last_level, saved_level; dwarf_vma cu_offset; int offset_size; int initial_length_size; @@ -2115,7 +2120,7 @@ process_debug_info (struct dwarf_section *section, debug_information [unit].num_range_lists = 0; } - if (!do_loc) + if (!do_loc && dwarf_start_die == 0) { printf (_(" Compilation Unit @ offset 0x%s:\n"), dwarf_vmatoa ("x", cu_offset)); @@ -2176,6 +2181,8 @@ process_debug_info (struct dwarf_section *section, + debug_displays [abbrev_sec].section.size); level = 0; + last_level = level; + saved_level = -1; while (tags < start) { unsigned int bytes_read; @@ -2183,6 +2190,7 @@ process_debug_info (struct dwarf_section *section, unsigned long die_offset; abbrev_entry *entry; abbrev_attr *attr; + int do_printing = 1; die_offset = tags - section_begin; @@ -2219,12 +2227,30 @@ process_debug_info (struct dwarf_section *section, warn (_("Further warnings about bogus end-of-sibling markers suppressed\n")); } } + if (dwarf_start_die != 0 && level < saved_level) + return 1; continue; } if (!do_loc) - printf (_(" <%d><%lx>: Abbrev Number: %lu"), - level, die_offset, abbrev_number); + { + if (dwarf_start_die != 0 && die_offset < dwarf_start_die) + do_printing = 0; + else + { + if (dwarf_start_die != 0 && die_offset == dwarf_start_die) + saved_level = level; + do_printing = (dwarf_cutoff_level == -1 + || level < dwarf_cutoff_level); + if (do_printing) + printf (_(" <%d><%lx>: Abbrev Number: %lu"), + level, die_offset, abbrev_number); + else if (dwarf_cutoff_level == -1 + || last_level < dwarf_cutoff_level) + printf (_(" <%d><%lx>: ...\n"), level, die_offset); + last_level = level; + } + } /* Scan through the abbreviation list until we reach the correct entry. */ @@ -2235,7 +2261,7 @@ process_debug_info (struct dwarf_section *section, if (entry == NULL) { - if (!do_loc) + if (!do_loc && do_printing) { printf ("\n"); fflush (stdout); @@ -2245,7 +2271,7 @@ process_debug_info (struct dwarf_section *section, return 0; } - if (!do_loc) + if (!do_loc && do_printing) printf (" (%s)\n", get_TAG_name (entry->tag)); switch (entry->tag) @@ -2266,9 +2292,15 @@ process_debug_info (struct dwarf_section *section, for (attr = entry->first_attr; attr; attr = attr->next) { - if (! do_loc) + debug_info *arg; + + if (! do_loc && do_printing) /* Show the offset from where the tag was extracted. */ - printf (" <%2lx>", (unsigned long)(tags - section_begin)); + printf (" <%lx>", (unsigned long)(tags - section_begin)); + + arg = debug_information; + if (debug_information) + arg += unit; tags = read_and_display_attr (attr->attribute, attr->form, @@ -2276,8 +2308,8 @@ process_debug_info (struct dwarf_section *section, compunit.cu_pointer_size, offset_size, compunit.cu_version, - debug_information + unit, - do_loc, section); + arg, + do_loc || ! do_printing, section); } if (entry->children) diff --git a/binutils/dwarf.h b/binutils/dwarf.h index 62b57a6..07b95b0 100644 --- a/binutils/dwarf.h +++ b/binutils/dwarf.h @@ -200,6 +200,9 @@ extern int do_trace_abbrevs; extern int do_trace_aranges; extern int do_wide; +extern int dwarf_cutoff_level; +extern unsigned long dwarf_start_die; + extern void init_dwarf_regnames (unsigned int); extern void init_dwarf_regnames_i386 (void); extern void init_dwarf_regnames_x86_64 (void); diff --git a/binutils/objdump.c b/binutils/objdump.c index 8b6bc28..231a668 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -110,6 +110,7 @@ static bfd_vma start_address = (bfd_vma) -1; /* --start-address */ static bfd_vma stop_address = (bfd_vma) -1; /* --stop-address */ static int dump_debugging; /* --debugging */ static int dump_debugging_tags; /* --debugging-tags */ +static int suppress_bfd_header; static int dump_special_syms = 0; /* --special-syms */ static bfd_vma adjust_section_vma = 0; /* --adjust-vma */ static int file_start_context = 0; /* --file-start-context */ @@ -246,8 +247,11 @@ usage (FILE *stream, int status) --adjust-vma=OFFSET Add OFFSET to all displayed section addresses\n\ --special-syms Include special symbols in symbol dumps\n\ --prefix=PREFIX Add PREFIX to absolute paths for -S\n\ - --prefix-strip=LEVEL Strip initial directory names for -S\n\ -\n")); + --prefix-strip=LEVEL Strip initial directory names for -S\n")); + fprintf (stream, _("\ + --dwarf-depth=N Do not display DIEs at depth N or greater\n\ + --dwarf-start=N Display DIEs starting with N, at the same depth\n\ + or deeper\n\n")); list_supported_targets (program_name, stream); list_supported_architectures (program_name, stream); @@ -268,7 +272,9 @@ enum option_values OPTION_PREFIX, OPTION_PREFIX_STRIP, OPTION_INSN_WIDTH, - OPTION_ADJUST_VMA + OPTION_ADJUST_VMA, + OPTION_DWARF_DEPTH, + OPTION_DWARF_START }; static struct option long_options[]= @@ -316,6 +322,8 @@ static struct option long_options[]= {"prefix", required_argument, NULL, OPTION_PREFIX}, {"prefix-strip", required_argument, NULL, OPTION_PREFIX_STRIP}, {"insn-width", required_argument, NULL, OPTION_INSN_WIDTH}, + {"dwarf-depth", required_argument, 0, OPTION_DWARF_DEPTH}, + {"dwarf-start", required_argument, 0, OPTION_DWARF_START}, {0, no_argument, 0, 0} }; @@ -3079,7 +3087,7 @@ dump_bfd (bfd *abfd) bfd_map_over_sections (abfd, adjust_addresses, &has_reloc); } - if (! dump_debugging_tags) + if (! dump_debugging_tags && ! suppress_bfd_header) printf (_("\n%s: file format %s\n"), bfd_get_filename (abfd), abfd->xvec->name); if (dump_ar_hdrs) @@ -3088,7 +3096,7 @@ dump_bfd (bfd *abfd) dump_bfd_header (abfd); if (dump_private_headers) dump_bfd_private_header (abfd); - if (! dump_debugging_tags) + if (! dump_debugging_tags && ! suppress_bfd_header) putchar ('\n'); if (dump_section_headers) dump_headers (abfd); @@ -3476,6 +3484,19 @@ main (int argc, char **argv) else dwarf_select_sections_all (); break; + case OPTION_DWARF_DEPTH: + { + char *cp; + dwarf_cutoff_level = strtoul (optarg, & cp, 0); + } + break; + case OPTION_DWARF_START: + { + char *cp; + dwarf_start_die = strtoul (optarg, & cp, 0); + suppress_bfd_header = 1; + } + break; case 'G': dump_stab_section_info = TRUE; seenflag = TRUE; diff --git a/binutils/readelf.c b/binutils/readelf.c index c4df8d9..6c8b966 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -3073,6 +3073,8 @@ get_section_type_name (unsigned int sh_type) #define OPTION_DEBUG_DUMP 512 #define OPTION_DYN_SYMS 513 +#define OPTION_DWARF_DEPTH 514 +#define OPTION_DWARF_START 515 static struct option options[] = { @@ -3106,6 +3108,9 @@ static struct option options[] = #endif {"debug-dump", optional_argument, 0, OPTION_DEBUG_DUMP}, + {"dwarf-depth", required_argument, 0, OPTION_DWARF_DEPTH}, + {"dwarf-start", required_argument, 0, OPTION_DWARF_START}, + {"version", no_argument, 0, 'v'}, {"wide", no_argument, 0, 'W'}, {"help", no_argument, 0, 'H'}, @@ -3149,6 +3154,10 @@ usage (FILE * stream) =frames-interp,=str,=loc,=Ranges,=pubtypes,\n\ =gdb_index,=trace_info,=trace_abbrev,=trace_aranges]\n\ Display the contents of DWARF2 debug sections\n")); + fprintf (stream, _("\ + --dwarf-depth=N Do not display DIEs at depth N or greater\n\ + --dwarf-start=N Display DIEs starting with N, at the same depth\n\ + or deeper\n")); #ifdef SUPPORT_DISASSEMBLY fprintf (stream, _("\ -i --instruction-dump=\n\ @@ -3355,6 +3364,20 @@ parse_args (int argc, char ** argv) dwarf_select_sections_by_names (optarg); } break; + case OPTION_DWARF_DEPTH: + { + char *cp; + + dwarf_cutoff_level = strtoul (optarg, & cp, 0); + } + break; + case OPTION_DWARF_START: + { + char *cp; + + dwarf_start_die = strtoul (optarg, & cp, 0); + } + break; case OPTION_DYN_SYMS: do_dyn_syms++; break; diff --git a/binutils/testsuite/ChangeLog b/binutils/testsuite/ChangeLog index fb9ad82..816ce95 100644 --- a/binutils/testsuite/ChangeLog +++ b/binutils/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2011-04-28 Tom Tromey + + * binutils-all/objdump.W: Correct output. + 011-04-11 Kai Tietz * binutils-all/windres/windres.exp: Add '// cpparg