static bool show_raw = false;
static bool show_modules = false;
static bool show_debugname = false;
+static bool show_inlines = false;
static int maxframes = 256;
return name;
}
+static void
+print_frame (int nr, Dwarf_Addr pc, bool isactivation,
+ Dwarf_Addr pc_adjusted, Dwfl_Module *mod,
+ const char *symname, Dwarf_Die *cudie,
+ Dwarf_Die *die)
+{
+ int width = get_addr_width (mod);
+ printf ("#%-2u 0x%0*" PRIx64, nr, width, (uint64_t) pc);
+
+ if (show_activation)
+ printf ("%4s", ! isactivation ? "- 1" : "");
+
+ if (symname != NULL)
+ {
+#ifdef USE_DEMANGLE
+ // Require GNU v3 ABI by the "_Z" prefix.
+ if (! show_raw && symname[0] == '_' && symname[1] == 'Z')
+ {
+ int status = -1;
+ char *dsymname = __cxa_demangle (symname, demangle_buffer,
+ &demangle_buffer_len, &status);
+ if (status == 0)
+ symname = demangle_buffer = dsymname;
+ }
+#endif
+ printf (" %s", symname);
+ }
+
+ const char* fname;
+ Dwarf_Addr start;
+ fname = dwfl_module_info(mod, NULL, &start,
+ NULL, NULL, NULL, NULL, NULL);
+ if (show_module)
+ {
+ if (fname != NULL)
+ printf (" - %s", fname);
+ }
+
+ if (show_build_id)
+ {
+ const unsigned char *id;
+ GElf_Addr id_vaddr;
+ int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
+ if (id_len > 0)
+ {
+ printf ("\n [");
+ do
+ printf ("%02" PRIx8, *id++);
+ while (--id_len > 0);
+ printf ("]@0x%0" PRIx64 "+0x%" PRIx64,
+ start, pc_adjusted - start);
+ }
+ }
+
+ if (show_source)
+ {
+ int line, col;
+ const char* sname;
+ line = col = -1;
+ sname = NULL;
+ if (die != NULL)
+ {
+ Dwarf_Files *files;
+ if (dwarf_getsrcfiles (cudie, &files, NULL) == 0)
+ {
+ Dwarf_Attribute attr;
+ Dwarf_Word val;
+ if (dwarf_formudata (dwarf_attr (die, DW_AT_call_file, &attr),
+ &val) == 0)
+ {
+ sname = dwarf_filesrc (files, val, NULL, NULL);
+ if (dwarf_formudata (dwarf_attr (die, DW_AT_call_line,
+ &attr), &val) == 0)
+ {
+ line = val;
+ if (dwarf_formudata (dwarf_attr (die, DW_AT_call_column,
+ &attr), &val) == 0)
+ col = val;
+ }
+ }
+ }
+ }
+ else
+ {
+ Dwfl_Line *lineobj = dwfl_module_getsrc(mod, pc_adjusted);
+ if (lineobj)
+ sname = dwfl_lineinfo (lineobj, NULL, &line, &col, NULL, NULL);
+ }
+
+ if (sname != NULL)
+ {
+ printf ("\n %s", sname);
+ if (line > 0)
+ {
+ printf (":%d", line);
+ if (col > 0)
+ printf (":%d", col);
+ }
+ }
+ }
+ printf ("\n");
+}
+
+static void
+print_inline_frames (int *nr, Dwarf_Addr pc, bool isactivation,
+ Dwarf_Addr pc_adjusted, Dwfl_Module *mod,
+ const char *symname, Dwarf_Die *cudie, Dwarf_Die *die)
+{
+ Dwarf_Die *scopes = NULL;
+ int nscopes = dwarf_getscopes_die (die, &scopes);
+ if (nscopes > 0)
+ {
+ /* scopes[0] == die, the lowest level, for which we already have
+ the name. This is the actual source location where it
+ happened. */
+ print_frame ((*nr)++, pc, isactivation, pc_adjusted, mod, symname,
+ NULL, NULL);
+
+ /* last_scope is the source location where the next frame/function
+ call was done. */
+ Dwarf_Die *last_scope = &scopes[0];
+ for (int i = 1; i < nscopes && (maxframes == 0 || *nr < maxframes); i++)
+ {
+ Dwarf_Die *scope = &scopes[i];
+ int tag = dwarf_tag (scope);
+ if (tag != DW_TAG_inlined_subroutine
+ && tag != DW_TAG_entry_point
+ && tag != DW_TAG_subprogram)
+ continue;
+
+ symname = die_name (scope);
+ print_frame ((*nr)++, pc, isactivation, pc_adjusted, mod, symname,
+ cudie, last_scope);
+
+ /* Found the "top-level" in which everything was inlined? */
+ if (tag == DW_TAG_subprogram)
+ break;
+
+ last_scope = scope;
+ }
+ }
+ free (scopes);
+}
+
static void
print_frames (struct frames *frames, pid_t tid, int dwflerr, const char *what)
{
frames_shown = true;
printf ("TID %d:\n", tid);
- for (int nr = 0; nr < frames->frames; nr++)
+ int frame_nr = 0;
+ for (int nr = 0; nr < frames->frames && (maxframes == 0
+ || frame_nr < maxframes); nr++)
{
Dwarf_Addr pc = frames->frame[nr].pc;
bool isactivation = frames->frame[nr].isactivation;
/* Get PC->SYMNAME. */
Dwfl_Module *mod = dwfl_addrmodule (dwfl, pc_adjusted);
const char *symname = NULL;
+ Dwarf_Die die_mem;
+ Dwarf_Die *die = NULL;
+ Dwarf_Die *cudie = NULL;
if (mod && ! show_quiet)
{
if (show_debugname)
{
Dwarf_Addr bias = 0;
- Dwarf_Die *cudie = dwfl_module_addrdie (mod, pc_adjusted, &bias);
Dwarf_Die *scopes = NULL;
+ cudie = dwfl_module_addrdie (mod, pc_adjusted, &bias);
int nscopes = dwarf_getscopes (cudie, pc_adjusted - bias,
&scopes);
|| tag == DW_TAG_inlined_subroutine
|| tag == DW_TAG_entry_point)
symname = die_name (scope);
+
+ if (symname != NULL)
+ {
+ die_mem = *scope;
+ die = &die_mem;
+ }
}
free (scopes);
}
symname = dwfl_module_addrname (mod, pc_adjusted);
}
- int width = get_addr_width (mod);
- printf ("#%-2u 0x%0*" PRIx64, nr, width, (uint64_t) pc);
-
- if (show_activation)
- printf ("%4s", ! isactivation ? "- 1" : "");
-
- if (symname != NULL)
- {
-#ifdef USE_DEMANGLE
- // Require GNU v3 ABI by the "_Z" prefix.
- if (! show_raw && symname[0] == '_' && symname[1] == 'Z')
- {
- int status = -1;
- char *dsymname = __cxa_demangle (symname, demangle_buffer,
- &demangle_buffer_len, &status);
- if (status == 0)
- symname = demangle_buffer = dsymname;
- }
-#endif
- printf (" %s", symname);
- }
-
- const char* fname;
- Dwarf_Addr start;
- fname = dwfl_module_info(mod, NULL, &start,
- NULL, NULL, NULL, NULL, NULL);
- if (show_module)
- {
- if (fname != NULL)
- printf (" - %s", fname);
- }
-
- if (show_build_id)
- {
- const unsigned char *id;
- GElf_Addr id_vaddr;
- int id_len = dwfl_module_build_id (mod, &id, &id_vaddr);
- if (id_len > 0)
- {
- printf ("\n [");
- do
- printf ("%02" PRIx8, *id++);
- while (--id_len > 0);
- printf ("]@0x%0" PRIx64 "+0x%" PRIx64,
- start, pc_adjusted - start);
- }
- }
-
- if (show_source)
- {
- Dwfl_Line *lineobj = dwfl_module_getsrc(mod, pc_adjusted);
- if (lineobj)
- {
- int line, col;
- const char* sname;
- line = col = -1;
- sname = dwfl_lineinfo (lineobj, NULL, &line, &col, NULL, NULL);
- if (sname != NULL)
- {
- printf ("\n %s", sname);
- if (line > 0)
- {
- printf (":%d", line);
- if (col > 0)
- printf (":%d", col);
- }
- }
- }
- }
- printf ("\n");
+ if (show_inlines && die != NULL)
+ print_inline_frames (&frame_nr, pc, isactivation, pc_adjusted, mod,
+ symname, cudie, die);
+ else
+ print_frame (frame_nr++, pc, isactivation, pc_adjusted, mod, symname,
+ NULL, NULL);
}
- if (dwflerr != 0)
+
+ if (frames->frames > 0 && frame_nr == maxframes)
+ error (0, 0, "tid %d: shown max number of frames "
+ "(%d, use -n 0 for unlimited)", tid, maxframes);
+ else if (dwflerr != 0)
{
if (frames->frames > 0)
{
else
error (0, 0, "%s tid %d: %s", what, tid, dwfl_errmsg (dwflerr));
}
- else if (frames->frames > 0 && frames->frames == maxframes)
- error (0, 0, "tid %d: shown max number of frames "
- "(%d, use -n 0 for unlimited)", tid, maxframes);
}
static int
show_debugname = true;
break;
+ case 'i':
+ show_inlines = show_debugname = true;
+ break;
+
case 'v':
show_activation = show_source = show_module = show_debugname = true;
+ show_inlines = true;
break;
case 'b':
{ "debugname", 'd', NULL, 0,
N_("Additionally try to lookup DWARF debuginfo name for frame address"),
0 },
+ { "inlines", 'i', NULL, 0,
+ N_("Additionally show inlined function frames using DWARF debuginfo if available (implies -d)"), 0 },
{ "module", 'm', NULL, 0,
N_("Additionally show module file information"), 0 },
{ "source", 's', NULL, 0,
N_("Additionally show source file information"), 0 },
{ "verbose", 'v', NULL, 0,
- N_("Show all additional information (activation, debugname, module and source)"), 0 },
+ N_("Show all additional information (activation, debugname, inlines, module and source)"), 0 },
{ "quiet", 'q', NULL, 0,
N_("Do not resolve address to function symbol name"), 0 },
{ "raw", 'r', NULL, 0,
--- /dev/null
+#! /bin/sh
+# Copyright (C) 2014 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file 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.
+#
+# elfutils 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, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# See run-stack-d-test.sh for dwarfinlines.cpp source.
+testfiles testfiledwarfinlines testfiledwarfinlines.core
+
+# Depending on whether we are running make check or make installcheck
+# the actual binary name under test might be different. It is used in
+# the error message, which we also try to match.
+if test "$elfutils_testrun" = "installed"; then
+STACKCMD=${bindir}/`program_transform stack`
+else
+STACKCMD=${abs_top_builddir}/src/stack
+fi
+
+# Compare with run-stack-d-test.sh to see the output without --inlines.
+# Only two call frames are visible (there is a jump from main to fu or
+# fubar).
+
+# With --inlines we get all inlined calls. Note they share the same
+# address.
+testrun_compare ${abs_top_builddir}/src/stack -n 6 -i -e testfiledwarfinlines --core testfiledwarfinlines.core<<EOF
+PID 13654 - core
+TID 13654:
+#0 0x00000000004006c8 fubar
+#1 0x00000000004006c8 foobar
+#2 0x00000000004006c8 bar
+#3 0x00000000004006c8 foo
+#4 0x00000000004006c8 fu(int)
+#5 0x00000000004004c5 main
+$STACKCMD: tid 13654: shown max number of frames (6, use -n 0 for unlimited)
+EOF
+
+# With --source we can also see where in the source the inlined frames
+# where originally called from.
+testrun_compare ${abs_top_builddir}/src/stack -n 6 -s -i -e testfiledwarfinlines --core testfiledwarfinlines.core<<EOF
+PID 13654 - core
+TID 13654:
+#0 0x00000000004006c8 fubar
+ /home/mark/src/tests/dwarfinlines.cpp:6
+#1 0x00000000004006c8 foobar
+ /home/mark/src/tests/dwarfinlines.cpp:14
+#2 0x00000000004006c8 bar
+ /home/mark/src/tests/dwarfinlines.cpp:21
+#3 0x00000000004006c8 foo
+ /home/mark/src/tests/dwarfinlines.cpp:27
+#4 0x00000000004006c8 fu(int)
+ /home/mark/src/tests/dwarfinlines.cpp:33
+#5 0x00000000004004c5 main
+ /home/mark/src/tests/dwarfinlines.cpp:39
+$STACKCMD: tid 13654: shown max number of frames (6, use -n 0 for unlimited)
+EOF
+
+exit 0