• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Locate source files and line information for given addresses
2    Copyright (C) 2005, 2006, 2007, 2008 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 
50 /* Name and version of program.  */
51 static void print_version (FILE *stream, struct argp_state *state);
52 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
53 
54 /* Bug report address.  */
55 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
56 
57 
58 /* Values for the parameters which have no short form.  */
59 #define OPT_DEMANGLER 0x100
60 
61 /* Definitions of arguments for argp functions.  */
62 static const struct argp_option options[] =
63 {
64   { NULL, 0, NULL, 0, N_("Output selection options:"), 2 },
65   { "basenames", 's', NULL, 0, N_("Show only base names of source files"), 0 },
66   { "absolute", 'A', NULL, 0,
67     N_("Show absolute file names using compilation directory"), 0 },
68   { "functions", 'f', NULL, 0, N_("Also show function names"), 0 },
69   { "symbols", 'S', NULL, 0, N_("Also show symbol or section names"), 0 },
70 
71   { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
72   /* Unsupported options.  */
73   { "target", 'b', "ARG", OPTION_HIDDEN, NULL, 0 },
74   { "demangle", 'C', "ARG", OPTION_HIDDEN | OPTION_ARG_OPTIONAL, NULL, 0 },
75   { "demangler", OPT_DEMANGLER, "ARG", OPTION_HIDDEN, NULL, 0 },
76   { NULL, 0, NULL, 0, NULL, 0 }
77 };
78 
79 /* Short description of program.  */
80 static const char doc[] = N_("\
81 Locate source files and line information for ADDRs (in a.out by default).");
82 
83 /* Strings for arguments in help texts.  */
84 static const char args_doc[] = N_("[ADDR...]");
85 
86 /* Prototype for option handler.  */
87 static error_t parse_opt (int key, char *arg, struct argp_state *state);
88 
89 static struct argp_child argp_children[2]; /* [0] is set in main.  */
90 
91 /* Data structure to communicate with argp functions.  */
92 static const struct argp argp =
93 {
94   options, parse_opt, args_doc, doc, argp_children, NULL, NULL
95 };
96 
97 
98 /* Handle ADDR.  */
99 static int handle_address (const char *addr, Dwfl *dwfl);
100 
101 
102 /* True if only base names of files should be shown.  */
103 static bool only_basenames;
104 
105 /* True if absolute file names based on DW_AT_comp_dir should be shown.  */
106 static bool use_comp_dir;
107 
108 /* True if function names should be shown.  */
109 static bool show_functions;
110 
111 /* True if ELF symbol or section info should be shown.  */
112 static bool show_symbols;
113 
114 
115 int
main(int argc,char * argv[])116 main (int argc, char *argv[])
117 {
118   int remaining;
119   int result = 0;
120 
121   /* Make memory leak detection possible.  */
122   mtrace ();
123 
124   /* We use no threads here which can interfere with handling a stream.  */
125   (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
126 
127   /* Set locale.  */
128   (void) setlocale (LC_ALL, "");
129 
130   /* Make sure the message catalog can be found.  */
131   (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
132 
133   /* Initialize the message catalog.  */
134   (void) textdomain (PACKAGE_TARNAME);
135 
136   /* Parse and process arguments.  This includes opening the modules.  */
137   argp_children[0].argp = dwfl_standard_argp ();
138   argp_children[0].group = 1;
139   Dwfl *dwfl = NULL;
140   (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
141   assert (dwfl != NULL);
142 
143   /* Now handle the addresses.  In case none are given on the command
144      line, read from stdin.  */
145   if (remaining == argc)
146     {
147       /* We use no threads here which can interfere with handling a stream.  */
148       (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
149 
150       char *buf = NULL;
151       size_t len = 0;
152       while (!feof_unlocked (stdin))
153 	{
154 	  if (getline (&buf, &len, stdin) < 0)
155 	    break;
156 
157 	  result = handle_address (buf, dwfl);
158 	}
159 
160       free (buf);
161     }
162   else
163     {
164       do
165 	result = handle_address (argv[remaining], dwfl);
166       while (++remaining < argc);
167     }
168 
169   return result;
170 }
171 
172 
173 /* Print the version information.  */
174 static void
print_version(FILE * stream,struct argp_state * state)175 print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
176 {
177   fprintf (stream, "addr2line (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
178   fprintf (stream, gettext ("\
179 Copyright (C) %s Red Hat, Inc.\n\
180 This is free software; see the source for copying conditions.  There is NO\n\
181 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
182 "), "2008");
183   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
184 }
185 
186 
187 /* Handle program arguments.  */
188 static error_t
parse_opt(int key,char * arg,struct argp_state * state)189 parse_opt (int key, char *arg __attribute__ ((unused)),
190 	   struct argp_state *state)
191 {
192   switch (key)
193     {
194     case ARGP_KEY_INIT:
195       state->child_inputs[0] = state->input;
196       break;
197 
198     case 'b':
199     case 'C':
200     case OPT_DEMANGLER:
201       /* Ignored for compatibility.  */
202       break;
203 
204     case 's':
205       only_basenames = true;
206       break;
207 
208     case 'A':
209       use_comp_dir = true;
210       break;
211 
212     case 'f':
213       show_functions = true;
214       break;
215 
216     case 'S':
217       show_symbols = true;
218       break;
219 
220     default:
221       return ARGP_ERR_UNKNOWN;
222     }
223   return 0;
224 }
225 
226 
227 static bool
print_dwarf_function(Dwfl_Module * mod,Dwarf_Addr addr)228 print_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr)
229 {
230   Dwarf_Addr bias = 0;
231   Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias);
232 
233   Dwarf_Die *scopes;
234   int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes);
235   if (nscopes <= 0)
236     return false;
237 
238   for (int i = 0; i < nscopes; ++i)
239     switch (dwarf_tag (&scopes[i]))
240       {
241       case DW_TAG_subprogram:
242 	{
243 	  const char *name = dwarf_diename (&scopes[i]);
244 	  if (name == NULL)
245 	    return false;
246 	  puts (name);
247 	  return true;
248 	}
249 
250       case DW_TAG_inlined_subroutine:
251 	{
252 	  const char *name = dwarf_diename (&scopes[i]);
253 	  if (name == NULL)
254 	    return false;
255 	  printf ("%s inlined", name);
256 
257 	  Dwarf_Files *files;
258 	  if (dwarf_getsrcfiles (cudie, &files, NULL) == 0)
259 	    {
260 	      Dwarf_Attribute attr_mem;
261 	      Dwarf_Word val;
262 	      if (dwarf_formudata (dwarf_attr (&scopes[i],
263 					       DW_AT_call_file,
264 					       &attr_mem), &val) == 0)
265 		{
266 		  const char *file = dwarf_filesrc (files, val, NULL, NULL);
267 		  unsigned int lineno = 0;
268 		  unsigned int colno = 0;
269 		  if (dwarf_formudata (dwarf_attr (&scopes[i],
270 						   DW_AT_call_line,
271 						   &attr_mem), &val) == 0)
272 		    lineno = val;
273 		  if (dwarf_formudata (dwarf_attr (&scopes[i],
274 						   DW_AT_call_column,
275 						   &attr_mem), &val) == 0)
276 		    colno = val;
277 		  if (lineno == 0)
278 		    {
279 		      if (file != NULL)
280 			printf (" from %s", file);
281 		    }
282 		  else if (colno == 0)
283 		    printf (" at %s:%u", file, lineno);
284 		  else
285 		    printf (" at %s:%u:%u", file, lineno, colno);
286 		}
287 	    }
288 	  printf (" in ");
289 	  continue;
290 	}
291       }
292 
293   return false;
294 }
295 
296 static void
print_addrsym(Dwfl_Module * mod,GElf_Addr addr)297 print_addrsym (Dwfl_Module *mod, GElf_Addr addr)
298 {
299   GElf_Sym s;
300   GElf_Word shndx;
301   const char *name = dwfl_module_addrsym (mod, addr, &s, &shndx);
302   if (name == NULL)
303     {
304       /* No symbol name.  Get a section name instead.  */
305       int i = dwfl_module_relocate_address (mod, &addr);
306       if (i >= 0)
307 	name = dwfl_module_relocation_info (mod, i, NULL);
308       if (name == NULL)
309 	puts ("??");
310       else
311 	printf ("(%s)+%#" PRIx64 "\n", name, addr);
312     }
313   else if (addr == s.st_value)
314     puts (name);
315   else
316     printf ("%s+%#" PRIx64 "\n", name, addr - s.st_value);
317 }
318 
319 static int
see_one_module(Dwfl_Module * mod,void ** userdata,const char * name,Dwarf_Addr start,void * arg)320 see_one_module (Dwfl_Module *mod,
321 		void **userdata __attribute__ ((unused)),
322 		const char *name __attribute__ ((unused)),
323 		Dwarf_Addr start __attribute__ ((unused)),
324 		void *arg)
325 {
326   Dwfl_Module **result = arg;
327   if (*result != NULL)
328     return DWARF_CB_ABORT;
329   *result = mod;
330   return DWARF_CB_OK;
331 }
332 
333 static int
find_symbol(Dwfl_Module * mod,void ** userdata,const char * name,Dwarf_Addr start,void * arg)334 find_symbol (Dwfl_Module *mod,
335 	     void **userdata __attribute__ ((unused)),
336 	     const char *name __attribute__ ((unused)),
337 	     Dwarf_Addr start __attribute__ ((unused)),
338 	     void *arg)
339 {
340   const char *looking_for = ((void **) arg)[0];
341   GElf_Sym *symbol = ((void **) arg)[1];
342 
343   int n = dwfl_module_getsymtab (mod);
344   for (int i = 1; i < n; ++i)
345     {
346       const char *symbol_name = dwfl_module_getsym (mod, i, symbol, NULL);
347       if (symbol_name == NULL)
348 	continue;
349       switch (GELF_ST_TYPE (symbol->st_info))
350 	{
351 	case STT_SECTION:
352 	case STT_FILE:
353 	case STT_TLS:
354 	  break;
355 	default:
356 	  if (!strcmp (symbol_name, looking_for))
357 	    {
358 	      ((void **) arg)[0] = NULL;
359 	      return DWARF_CB_ABORT;
360 	    }
361 	}
362     }
363 
364   return DWARF_CB_OK;
365 }
366 
367 static int
handle_address(const char * string,Dwfl * dwfl)368 handle_address (const char *string, Dwfl *dwfl)
369 {
370   char *endp;
371   uintmax_t addr = strtoumax (string, &endp, 0);
372   if (endp == string)
373     {
374       bool parsed = false;
375       int n;
376       char *name = NULL;
377       if (sscanf (string, "(%m[^)])%" PRIiMAX "%n", &name, &addr, &n) == 2
378 	  && string[n] == '\0')
379 	{
380 	  /* It was (section)+offset.  This makes sense if there is
381 	     only one module to look in for a section.  */
382 	  Dwfl_Module *mod = NULL;
383 	  if (dwfl_getmodules (dwfl, &see_one_module, &mod, 0) != 0
384 	      || mod == NULL)
385 	    error (EXIT_FAILURE, 0, gettext ("Section syntax requires"
386 					     " exactly one module"));
387 
388 	  int nscn = dwfl_module_relocations (mod);
389 	  for (int i = 0; i < nscn; ++i)
390 	    {
391 	      GElf_Word shndx;
392 	      const char *scn = dwfl_module_relocation_info (mod, i, &shndx);
393 	      if (unlikely (scn == NULL))
394 		break;
395 	      if (!strcmp (scn, name))
396 		{
397 		  /* Found the section.  */
398 		  GElf_Shdr shdr_mem;
399 		  GElf_Addr shdr_bias;
400 		  GElf_Shdr *shdr = gelf_getshdr
401 		    (elf_getscn (dwfl_module_getelf (mod, &shdr_bias), shndx),
402 		     &shdr_mem);
403 		  if (unlikely (shdr == NULL))
404 		    break;
405 
406 		  if (addr >= shdr->sh_size)
407 		    error (0, 0,
408 			   gettext ("offset %#" PRIxMAX " lies outside"
409 				    " section '%s'"),
410 			   addr, scn);
411 
412 		  addr += shdr->sh_addr + shdr_bias;
413 		  parsed = true;
414 		  break;
415 		}
416 	    }
417 	}
418       else if (sscanf (string, "%m[^-+]%" PRIiMAX "%n", &name, &addr, &n) == 2
419 	       && string[n] == '\0')
420 	{
421 	  /* It was symbol+offset.  */
422 	  GElf_Sym sym;
423 	  void *arg[2] = { name, &sym };
424 	  (void) dwfl_getmodules (dwfl, &find_symbol, arg, 0);
425 	  if (arg[0] != NULL)
426 	    error (0, 0, gettext ("cannot find symbol '%s'"), name);
427 	  else
428 	    {
429 	      if (sym.st_size != 0 && addr >= sym.st_size)
430 		error (0, 0,
431 		       gettext ("offset %#" PRIxMAX " lies outside"
432 				" contents of '%s'"),
433 		       addr, name);
434 	      addr += sym.st_value;
435 	      parsed = true;
436 	    }
437 	}
438 
439       free (name);
440       if (!parsed)
441 	return 1;
442     }
443 
444   Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr);
445 
446   if (show_functions)
447     {
448       /* First determine the function name.  Use the DWARF information if
449 	 possible.  */
450       if (! print_dwarf_function (mod, addr) && !show_symbols)
451 	puts (dwfl_module_addrname (mod, addr) ?: "??");
452     }
453 
454   if (show_symbols)
455     print_addrsym (mod, addr);
456 
457   Dwfl_Line *line = dwfl_module_getsrc (mod, addr);
458 
459   const char *src;
460   int lineno, linecol;
461   if (line != NULL && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol,
462 					    NULL, NULL)) != NULL)
463     {
464       const char *comp_dir = "";
465       const char *comp_dir_sep = "";
466 
467       if (only_basenames)
468 	src = basename (src);
469       else if (use_comp_dir && src[0] != '/')
470 	{
471 	  comp_dir = dwfl_line_comp_dir (line);
472 	  if (comp_dir != NULL)
473 	    comp_dir_sep = "/";
474 	}
475 
476       if (linecol != 0)
477 	printf ("%s%s%s:%d:%d\n",
478 		comp_dir, comp_dir_sep, src, lineno, linecol);
479       else
480 	printf ("%s%s%s:%d\n",
481 		comp_dir, comp_dir_sep, src, lineno);
482     }
483   else
484     puts ("??:0");
485 
486   return 0;
487 }
488 
489 
490 #include "debugpred.h"
491