1/* Locate source files and line information for given addresses
2   Copyright (C) 2005-2010, 2012 Red Hat, Inc.
3   This file is part of Red Hat elfutils.
4   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
5
6   Red Hat elfutils is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by the
8   Free Software Foundation; version 2 of the License.
9
10   Red Hat elfutils is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   General Public License for more details.
14
15   You should have received a copy of the GNU General Public License along
16   with Red Hat elfutils; if not, write to the Free Software Foundation,
17   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18
19   Red Hat elfutils is an included package of the Open Invention Network.
20   An included package of the Open Invention Network is a package for which
21   Open Invention Network licensees cross-license their patents.  No patent
22   license is granted, either expressly or impliedly, by designation as an
23   included package.  Should you wish to participate in the Open Invention
24   Network licensing program, please visit www.openinventionnetwork.com
25   <http://www.openinventionnetwork.com>.  */
26
27#ifdef HAVE_CONFIG_H
28# include <config.h>
29#endif
30
31#include <argp.h>
32#include <assert.h>
33#include <errno.h>
34#include <error.h>
35#include <fcntl.h>
36#include <inttypes.h>
37#include <libdwfl.h>
38#include <dwarf.h>
39#include <libintl.h>
40#include <locale.h>
41#include <mcheck.h>
42#include <stdbool.h>
43#include <stdio.h>
44#include <stdio_ext.h>
45#include <stdlib.h>
46#include <string.h>
47#include <unistd.h>
48
49#include <system.h>
50
51
52/* Name and version of program.  */
53static void print_version (FILE *stream, struct argp_state *state);
54ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
55
56/* Bug report address.  */
57ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
58
59
60/* Values for the parameters which have no short form.  */
61#define OPT_DEMANGLER 0x100
62
63/* Definitions of arguments for argp functions.  */
64static const struct argp_option options[] =
65{
66  { NULL, 0, NULL, 0, N_("Output selection options:"), 2 },
67  { "basenames", 's', NULL, 0, N_("Show only base names of source files"), 0 },
68  { "absolute", 'A', NULL, 0,
69    N_("Show absolute file names using compilation directory"), 0 },
70  { "functions", 'f', NULL, 0, N_("Also show function names"), 0 },
71  { "symbols", 'S', NULL, 0, N_("Also show symbol or section names"), 0 },
72  { "flags", 'F', NULL, 0, N_("Also show line table flags"), 0 },
73  { "section", 'j', "NAME", 0,
74    N_("Treat addresses as offsets relative to NAME section."), 0 },
75
76  { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
77  /* Unsupported options.  */
78  { "target", 'b', "ARG", OPTION_HIDDEN, NULL, 0 },
79  { "demangle", 'C', "ARG", OPTION_HIDDEN | OPTION_ARG_OPTIONAL, NULL, 0 },
80  { "demangler", OPT_DEMANGLER, "ARG", OPTION_HIDDEN, NULL, 0 },
81  { NULL, 0, NULL, 0, NULL, 0 }
82};
83
84/* Short description of program.  */
85static const char doc[] = N_("\
86Locate source files and line information for ADDRs (in a.out by default).");
87
88/* Strings for arguments in help texts.  */
89static const char args_doc[] = N_("[ADDR...]");
90
91/* Prototype for option handler.  */
92static error_t parse_opt (int key, char *arg, struct argp_state *state);
93
94static struct argp_child argp_children[2]; /* [0] is set in main.  */
95
96/* Data structure to communicate with argp functions.  */
97static const struct argp argp =
98{
99  options, parse_opt, args_doc, doc, argp_children, NULL, NULL
100};
101
102
103/* Handle ADDR.  */
104static int handle_address (const char *addr, Dwfl *dwfl);
105
106
107/* True if only base names of files should be shown.  */
108static bool only_basenames;
109
110/* True if absolute file names based on DW_AT_comp_dir should be shown.  */
111static bool use_comp_dir;
112
113/* True if line flags should be shown.  */
114static bool show_flags;
115
116/* True if function names should be shown.  */
117static bool show_functions;
118
119/* True if ELF symbol or section info should be shown.  */
120static bool show_symbols;
121
122/* If non-null, take address parameters as relative to named section.  */
123static const char *just_section;
124
125
126int
127main (int argc, char *argv[])
128{
129  int remaining;
130  int result = 0;
131
132  /* Make memory leak detection possible.  */
133  mtrace ();
134
135  /* We use no threads here which can interfere with handling a stream.  */
136  (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
137
138  /* Set locale.  */
139  (void) setlocale (LC_ALL, "");
140
141  /* Make sure the message catalog can be found.  */
142  (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
143
144  /* Initialize the message catalog.  */
145  (void) textdomain (PACKAGE_TARNAME);
146
147  /* Parse and process arguments.  This includes opening the modules.  */
148  argp_children[0].argp = dwfl_standard_argp ();
149  argp_children[0].group = 1;
150  Dwfl *dwfl = NULL;
151  (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
152  assert (dwfl != NULL);
153
154  /* Now handle the addresses.  In case none are given on the command
155     line, read from stdin.  */
156  if (remaining == argc)
157    {
158      /* We use no threads here which can interfere with handling a stream.  */
159      (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
160
161      char *buf = NULL;
162      size_t len = 0;
163      while (!feof_unlocked (stdin))
164	{
165	  if (getline (&buf, &len, stdin) < 0)
166	    break;
167
168	  result = handle_address (buf, dwfl);
169	}
170
171      free (buf);
172    }
173  else
174    {
175      do
176	result = handle_address (argv[remaining], dwfl);
177      while (++remaining < argc);
178    }
179
180  return result;
181}
182
183
184/* Print the version information.  */
185static void
186print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
187{
188  fprintf (stream, "addr2line (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
189  fprintf (stream, gettext ("\
190Copyright (C) %s Red Hat, Inc.\n\
191This is free software; see the source for copying conditions.  There is NO\n\
192warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
193"), "2012");
194  fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
195}
196
197
198/* Handle program arguments.  */
199static error_t
200parse_opt (int key, char *arg, struct argp_state *state)
201{
202  switch (key)
203    {
204    case ARGP_KEY_INIT:
205      state->child_inputs[0] = state->input;
206      break;
207
208    case 'b':
209    case 'C':
210    case OPT_DEMANGLER:
211      /* Ignored for compatibility.  */
212      break;
213
214    case 's':
215      only_basenames = true;
216      break;
217
218    case 'A':
219      use_comp_dir = true;
220      break;
221
222    case 'f':
223      show_functions = true;
224      break;
225
226    case 'F':
227      show_flags = true;
228      break;
229
230    case 'S':
231      show_symbols = true;
232      break;
233
234    case 'j':
235      just_section = arg;
236      break;
237
238    default:
239      return ARGP_ERR_UNKNOWN;
240    }
241  return 0;
242}
243
244
245static bool
246print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
247{
248  Dwarf_Addr bias = 0;
249  Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias);
250
251  Dwarf_Die *scopes;
252  int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes);
253  if (nscopes <= 0)
254    return false;
255
256  for (int i = 0; i < nscopes; ++i)
257    switch (dwarf_tag (&scopes[i]))
258      {
259      case DW_TAG_subprogram:
260	{
261	  const char *name = dwarf_diename (&scopes[i]);
262	  if (name == NULL)
263	    return false;
264	  puts (name);
265	  return true;
266	}
267
268      case DW_TAG_inlined_subroutine:
269	{
270	  const char *name = dwarf_diename (&scopes[i]);
271	  if (name == NULL)
272	    return false;
273	  printf ("%s inlined", name);
274
275	  Dwarf_Files *files;
276	  if (dwarf_getsrcfiles (cudie, &files, NULL) == 0)
277	    {
278	      Dwarf_Attribute attr_mem;
279	      Dwarf_Word val;
280	      if (dwarf_formudata (dwarf_attr (&scopes[i],
281					       DW_AT_call_file,
282					       &attr_mem), &val) == 0)
283		{
284		  const char *file = dwarf_filesrc (files, val, NULL, NULL);
285		  unsigned int lineno = 0;
286		  unsigned int colno = 0;
287		  if (dwarf_formudata (dwarf_attr (&scopes[i],
288						   DW_AT_call_line,
289						   &attr_mem), &val) == 0)
290		    lineno = val;
291		  if (dwarf_formudata (dwarf_attr (&scopes[i],
292						   DW_AT_call_column,
293						   &attr_mem), &val) == 0)
294		    colno = val;
295
296		  const char *comp_dir = "";
297		  const char *comp_dir_sep = "";
298
299		  if (file == NULL)
300		    file = "???";
301		  else if (only_basenames)
302		    file = basename (file);
303		  else if (use_comp_dir && file[0] != '/')
304		    {
305		      const char *const *dirs;
306		      size_t ndirs;
307		      if (dwarf_getsrcdirs (files, &dirs, &ndirs) == 0
308			  && dirs[0] != NULL)
309			{
310			  comp_dir = dirs[0];
311			  comp_dir_sep = "/";
312			}
313		    }
314
315		  if (lineno == 0)
316		    printf (" from %s%s%s",
317			    comp_dir, comp_dir_sep, file);
318		  else if (colno == 0)
319		    printf (" at %s%s%s:%u",
320			    comp_dir, comp_dir_sep, file, lineno);
321		  else
322		    printf (" at %s%s%s:%u:%u",
323			    comp_dir, comp_dir_sep, file, lineno, colno);
324		}
325	    }
326	  printf (" in ");
327	  continue;
328	}
329      }
330
331  return false;
332}
333
334static void
335print_addrsym (Dwfl_Module *mod, GElf_Addr addr)
336{
337  GElf_Sym s;
338  GElf_Word shndx;
339  const char *name = dwfl_module_addrsym (mod, addr, &s, &shndx);
340  if (name == NULL)
341    {
342      /* No symbol name.  Get a section name instead.  */
343      int i = dwfl_module_relocate_address (mod, &addr);
344      if (i >= 0)
345	name = dwfl_module_relocation_info (mod, i, NULL);
346      if (name == NULL)
347	puts ("??");
348      else
349	printf ("(%s)+%#" PRIx64 "\n", name, addr);
350    }
351  else if (addr == s.st_value)
352    puts (name);
353  else
354    printf ("%s+%#" PRIx64 "\n", name, addr - s.st_value);
355}
356
357static int
358see_one_module (Dwfl_Module *mod,
359		void **userdata __attribute__ ((unused)),
360		const char *name __attribute__ ((unused)),
361		Dwarf_Addr start __attribute__ ((unused)),
362		void *arg)
363{
364  Dwfl_Module **result = arg;
365  if (*result != NULL)
366    return DWARF_CB_ABORT;
367  *result = mod;
368  return DWARF_CB_OK;
369}
370
371static int
372find_symbol (Dwfl_Module *mod,
373	     void **userdata __attribute__ ((unused)),
374	     const char *name __attribute__ ((unused)),
375	     Dwarf_Addr start __attribute__ ((unused)),
376	     void *arg)
377{
378  const char *looking_for = ((void **) arg)[0];
379  GElf_Sym *symbol = ((void **) arg)[1];
380
381  int n = dwfl_module_getsymtab (mod);
382  for (int i = 1; i < n; ++i)
383    {
384      const char *symbol_name = dwfl_module_getsym (mod, i, symbol, NULL);
385      if (symbol_name == NULL || symbol_name[0] == '\0')
386	continue;
387      switch (GELF_ST_TYPE (symbol->st_info))
388	{
389	case STT_SECTION:
390	case STT_FILE:
391	case STT_TLS:
392	  break;
393	default:
394	  if (!strcmp (symbol_name, looking_for))
395	    {
396	      ((void **) arg)[0] = NULL;
397	      return DWARF_CB_ABORT;
398	    }
399	}
400    }
401
402  return DWARF_CB_OK;
403}
404
405static bool
406adjust_to_section (const char *name, uintmax_t *addr, Dwfl *dwfl)
407{
408  /* It was (section)+offset.  This makes sense if there is
409     only one module to look in for a section.  */
410  Dwfl_Module *mod = NULL;
411  if (dwfl_getmodules (dwfl, &see_one_module, &mod, 0) != 0
412      || mod == NULL)
413    error (EXIT_FAILURE, 0, gettext ("Section syntax requires"
414				     " exactly one module"));
415
416  int nscn = dwfl_module_relocations (mod);
417  for (int i = 0; i < nscn; ++i)
418    {
419      GElf_Word shndx;
420      const char *scn = dwfl_module_relocation_info (mod, i, &shndx);
421      if (unlikely (scn == NULL))
422	break;
423      if (!strcmp (scn, name))
424	{
425	  /* Found the section.  */
426	  GElf_Shdr shdr_mem;
427	  GElf_Addr shdr_bias;
428	  GElf_Shdr *shdr = gelf_getshdr
429	    (elf_getscn (dwfl_module_getelf (mod, &shdr_bias), shndx),
430	     &shdr_mem);
431	  if (unlikely (shdr == NULL))
432	    break;
433
434	  if (*addr >= shdr->sh_size)
435	    error (0, 0,
436		   gettext ("offset %#" PRIxMAX " lies outside"
437			    " section '%s'"),
438		   *addr, scn);
439
440	  *addr += shdr->sh_addr + shdr_bias;
441	  return true;
442	}
443    }
444
445  return false;
446}
447
448static int
449handle_address (const char *string, Dwfl *dwfl)
450{
451  char *endp;
452  uintmax_t addr = strtoumax (string, &endp, 0);
453  if (endp == string)
454    {
455      bool parsed = false;
456      int i, j;
457      char *name = NULL;
458      if (sscanf (string, "(%m[^)])%" PRIiMAX "%n", &name, &addr, &i) == 2
459	  && string[i] == '\0')
460	parsed = adjust_to_section (name, &addr, dwfl);
461      switch (sscanf (string, "%m[^-+]%n%" PRIiMAX "%n", &name, &i, &addr, &j))
462	{
463	default:
464	  break;
465	case 1:
466	  addr = 0;
467	  j = i;
468	case 2:
469	  if (string[j] != '\0')
470	    break;
471
472	  /* It was symbol[+offset].  */
473	  GElf_Sym sym;
474	  void *arg[2] = { name, &sym };
475	  (void) dwfl_getmodules (dwfl, &find_symbol, arg, 0);
476	  if (arg[0] != NULL)
477	    error (0, 0, gettext ("cannot find symbol '%s'"), name);
478	  else
479	    {
480	      if (sym.st_size != 0 && addr >= sym.st_size)
481		error (0, 0,
482		       gettext ("offset %#" PRIxMAX " lies outside"
483				" contents of '%s'"),
484		       addr, name);
485	      addr += sym.st_value;
486	      parsed = true;
487	    }
488	  break;
489	}
490
491      free (name);
492      if (!parsed)
493	return 1;
494    }
495  else if (just_section != NULL
496	   && !adjust_to_section (just_section, &addr, dwfl))
497    return 1;
498
499  Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr);
500
501  if (show_functions)
502    {
503      /* First determine the function name.  Use the DWARF information if
504	 possible.  */
505      if (! print_dwarf_function (mod, addr) && !show_symbols)
506	puts (dwfl_module_addrname (mod, addr) ?: "??");
507    }
508
509  if (show_symbols)
510    print_addrsym (mod, addr);
511
512  Dwfl_Line *line = dwfl_module_getsrc (mod, addr);
513
514  const char *src;
515  int lineno, linecol;
516  if (line != NULL && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol,
517					    NULL, NULL)) != NULL)
518    {
519      const char *comp_dir = "";
520      const char *comp_dir_sep = "";
521
522      if (only_basenames)
523	src = basename (src);
524      else if (use_comp_dir && src[0] != '/')
525	{
526	  comp_dir = dwfl_line_comp_dir (line);
527	  if (comp_dir != NULL)
528	    comp_dir_sep = "/";
529	}
530
531      if (linecol != 0)
532	printf ("%s%s%s:%d:%d",
533		comp_dir, comp_dir_sep, src, lineno, linecol);
534      else
535	printf ("%s%s%s:%d",
536		comp_dir, comp_dir_sep, src, lineno);
537
538      if (show_flags)
539	{
540	  Dwarf_Addr bias;
541	  Dwarf_Line *info = dwfl_dwarf_line (line, &bias);
542	  assert (info != NULL);
543
544	  inline void show (int (*get) (Dwarf_Line *, bool *),
545			    const char *note)
546	  {
547	    bool flag;
548	    if ((*get) (info, &flag) == 0 && flag)
549	      fputs (note, stdout);
550	  }
551	  inline void show_int (int (*get) (Dwarf_Line *, unsigned int *),
552				const char *name)
553	  {
554	    unsigned int val;
555	    if ((*get) (info, &val) == 0 && val != 0)
556	      printf (" (%s %u)", name, val);
557	  }
558
559	  show (&dwarf_linebeginstatement, " (is_stmt)");
560	  show (&dwarf_lineblock, " (basic_block)");
561	  show (&dwarf_lineprologueend, " (prologue_end)");
562	  show (&dwarf_lineepiloguebegin, " (epilogue_begin)");
563	  show_int (&dwarf_lineisa, "isa");
564	  show_int (&dwarf_linediscriminator, "discriminator");
565	}
566      putchar ('\n');
567    }
568  else
569    puts ("??:0");
570
571  return 0;
572}
573
574
575#include "debugpred.h"
576