Add optional style argument to --demangle switch.
[external/binutils.git] / binutils / addr2line.c
1 /* addr2line.c -- convert addresses to line number and function name
2    Copyright 1997, 98, 99, 2000 Free Software Foundation, Inc.
3    Contributed by Ulrich Lauther <Ulrich.Lauther@zfe.siemens.de>
4
5    This file is part of GNU Binutils.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2, or (at your option)
10    any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 /* Derived from objdump.c and nm.c by Ulrich.Lauther@zfe.siemens.de
22
23    Usage: 
24    addr2line [options] addr addr ...
25    or
26    addr2line [options] 
27
28    both forms write results to stdout, the second form reads addresses
29    to be converted from stdin.  */
30
31 #include <ctype.h>
32 #include <string.h>
33
34 #include "bfd.h"
35 #include "getopt.h"
36 #include "libiberty.h"
37 #include "demangle.h"
38 #include "bucomm.h"
39
40 extern char *program_version;
41
42 static boolean with_functions;  /* -f, show function names.  */
43 static boolean do_demangle;     /* -C, demangle names.  */
44 static boolean base_names;      /* -s, strip directory names.  */
45
46 static int naddr;               /* Number of addresses to process.  */
47 static char **addr;             /* Hex addresses to process.  */
48
49 static asymbol **syms;          /* Symbol table.  */
50
51 static struct option long_options[] =
52 {
53   {"basenames", no_argument, NULL, 's'},
54   {"demangle", optional_argument, NULL, 'C'},
55   {"exe", required_argument, NULL, 'e'},
56   {"functions", no_argument, NULL, 'f'},
57   {"target", required_argument, NULL, 'b'},
58   {"help", no_argument, NULL, 'H'},
59   {"version", no_argument, NULL, 'V'},
60   {0, no_argument, 0, 0}
61 };
62
63 static void usage PARAMS ((FILE *, int));
64 static void slurp_symtab PARAMS ((bfd *));
65 static void find_address_in_section PARAMS ((bfd *, asection *, PTR));
66 static void translate_addresses PARAMS ((bfd *));
67 static void process_file PARAMS ((const char *, const char *));
68 \f
69 /* Print a usage message to STREAM and exit with STATUS.  */
70
71 static void
72 usage (stream, status)
73      FILE *stream;
74      int status;
75 {
76   fprintf (stream, _("\
77 Usage: %s [-CfsHV] [-b bfdname] [--target=bfdname]\n\
78        [-e executable] [--exe=executable] [--demangle[=style]]\n\
79        [--basenames] [--functions] [addr addr ...]\n"),
80            program_name);
81   list_supported_targets (program_name, stream);
82   if (status == 0)
83     fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
84   exit (status);
85 }
86 \f
87 /* Read in the symbol table.  */
88
89 static void
90 slurp_symtab (abfd)
91      bfd *abfd;
92 {
93   long storage;
94   long symcount;
95
96   if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0)
97     return;
98
99   storage = bfd_get_symtab_upper_bound (abfd);
100   if (storage < 0)
101     bfd_fatal (bfd_get_filename (abfd));
102
103   syms = (asymbol **) xmalloc (storage);
104
105   symcount = bfd_canonicalize_symtab (abfd, syms);
106   if (symcount < 0)
107     bfd_fatal (bfd_get_filename (abfd));
108 }
109 \f
110 /* These global variables are used to pass information between
111    translate_addresses and find_address_in_section.  */
112
113 static bfd_vma pc;
114 static const char *filename;
115 static const char *functionname;
116 static unsigned int line;
117 static boolean found;
118
119 /* Look for an address in a section.  This is called via
120    bfd_map_over_sections.  */
121
122 static void
123 find_address_in_section (abfd, section, data)
124      bfd *abfd;
125      asection *section;
126      PTR data ATTRIBUTE_UNUSED;
127 {
128   bfd_vma vma;
129   bfd_size_type size;
130
131   if (found)
132     return;
133
134   if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0)
135     return;
136
137   vma = bfd_get_section_vma (abfd, section);
138   if (pc < vma)
139     return;
140
141   size = bfd_get_section_size_before_reloc (section);
142   if (pc >= vma + size)
143     return;
144
145   found = bfd_find_nearest_line (abfd, section, syms, pc - vma,
146                                  &filename, &functionname, &line);
147 }
148
149 /* Read hexadecimal addresses from stdin, translate into
150    file_name:line_number and optionally function name.  */
151
152 static void
153 translate_addresses (abfd)
154      bfd *abfd;
155 {
156   int read_stdin = (naddr == 0);
157
158   for (;;)
159     {
160       if (read_stdin)
161         {
162           char addr_hex[100];
163
164           if (fgets (addr_hex, sizeof addr_hex, stdin) == NULL)
165             break;
166           pc = bfd_scan_vma (addr_hex, NULL, 16);
167         }
168       else
169         {
170           if (naddr <= 0)
171             break;
172           --naddr;
173           pc = bfd_scan_vma (*addr++, NULL, 16);
174         }
175
176       found = false;
177       bfd_map_over_sections (abfd, find_address_in_section, (PTR) NULL);
178
179       if (! found)
180         {
181           if (with_functions)
182             printf ("??\n");
183           printf ("??:0\n");
184         }
185       else
186         {
187           if (with_functions)
188             {
189               if (functionname == NULL || *functionname == '\0')
190                 printf ("??\n");
191               else if (! do_demangle)
192                 printf ("%s\n", functionname);
193               else
194                 {
195                   char *res;
196
197                   res = cplus_demangle (functionname, DMGL_ANSI | DMGL_PARAMS);
198                   if (res == NULL)
199                     printf ("%s\n", functionname);
200                   else
201                     {
202                       printf ("%s\n", res);
203                       free (res);
204                     }
205                 }
206             }
207
208           if (base_names && filename != NULL)
209             {
210               char *h;
211
212               h = strrchr (filename, '/');
213               if (h != NULL)
214                 filename = h + 1;
215             }
216
217           printf ("%s:%u\n", filename ? filename : "??", line);
218         }
219
220       /* fflush() is essential for using this command as a server
221          child process that reads addresses from a pipe and responds
222          with line number information, processing one address at a
223          time.  */
224       fflush (stdout);
225     }
226 }
227
228 /* Process a file.  */
229
230 static void
231 process_file (filename, target)
232      const char *filename;
233      const char *target;
234 {
235   bfd *abfd;
236   char **matching;
237
238   abfd = bfd_openr (filename, target);
239   if (abfd == NULL)
240     bfd_fatal (filename);
241
242   if (bfd_check_format (abfd, bfd_archive))
243     fatal (_("%s: can not get addresses from archive"), filename);
244
245   if (! bfd_check_format_matches (abfd, bfd_object, &matching))
246     {
247       bfd_nonfatal (bfd_get_filename (abfd));
248       if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
249         {
250           list_matching_formats (matching);
251           free (matching);
252         }
253       xexit (1);
254     }
255
256   slurp_symtab (abfd);
257
258   translate_addresses (abfd);
259
260   if (syms != NULL)
261     {
262       free (syms);
263       syms = NULL;
264     }
265
266   bfd_close (abfd);
267 }
268 \f
269 int
270 main (argc, argv)
271      int argc;
272      char **argv;
273 {
274   char *filename;
275   char *target;
276   int c;
277
278 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
279   setlocale (LC_MESSAGES, "");
280 #endif
281   bindtextdomain (PACKAGE, LOCALEDIR);
282   textdomain (PACKAGE);
283
284   program_name = *argv;
285   xmalloc_set_program_name (program_name);
286
287   bfd_init ();
288   set_default_bfd_target ();
289
290   filename = NULL;
291   target = NULL;
292   while ((c = getopt_long (argc, argv, "b:Ce:sfHV", long_options, (int *) 0))
293          != EOF)
294     {
295       switch (c)
296         {
297         case 0:
298           break;                /* we've been given a long option */
299         case 'b':
300           target = optarg;
301           break;
302         case 'C':
303           do_demangle = true;
304           if (optarg != NULL)
305             {
306               enum demangling_styles style;
307               
308               style = cplus_demangle_name_to_style (optarg);
309               if (style == unknown_demangling) 
310                 fatal (_("unknown demangling style `%s'"),
311                        optarg);
312               
313               cplus_demangle_set_style (style);
314            }
315           break;
316         case 'e':
317           filename = optarg;
318           break;
319         case 's':
320           base_names = true;
321           break;
322         case 'f':
323           with_functions = true;
324           break;
325         case 'V':
326           print_version ("addr2line");
327           break;
328         case 'H':
329           usage (stdout, 0);
330           break;
331         default:
332           usage (stderr, 1);
333           break;
334         }
335     }
336
337   if (filename == NULL)
338     filename = "a.out";
339
340   addr = argv + optind;
341   naddr = argc - optind;
342
343   process_file (filename, target);
344
345   return 0;
346 }