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