Coverage Report

Created: 2023-06-29 07:13

/src/binutils-gdb/binutils/fuzz_addr2line.h
Line
Count
Source (jump to first uncovered line)
1
/* addr2line.c -- convert addresses to line number and function name
2
   Copyright (C) 1997-2023 Free Software Foundation, Inc.
3
   Contributed by Ulrich Lauther <Ulrich.Lauther@mchp.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 3, 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, 51 Franklin Street - Fifth Floor, Boston,
20
   MA 02110-1301, USA.  */
21
22
23
/* Derived from objdump.c and nm.c by Ulrich.Lauther@mchp.siemens.de
24
25
   Usage:
26
   addr2line [options] addr addr ...
27
   or
28
   addr2line [options]
29
30
   both forms write results to stdout, the second form reads addresses
31
   to be converted from stdin.  */
32
33
#include "sysdep.h"
34
#include "bfd.h"
35
#include "getopt.h"
36
#include "libiberty.h"
37
#include "demangle.h"
38
#include "bucomm.h"
39
#include "elf-bfd.h"
40
#include "safe-ctype.h"
41
42
static bool unwind_inlines; /* -i, unwind inlined functions. */
43
static bool with_addresses; /* -a, show addresses.  */
44
static bool with_functions; /* -f, show function names.  */
45
static bool do_demangle;  /* -C, demangle names.  */
46
static bool pretty_print; /* -p, print on one line.  */
47
static bool base_names;   /* -s, strip directory names.  */
48
49
/* Flags passed to the name demangler.  */
50
static int demangle_flags = DMGL_PARAMS | DMGL_ANSI;
51
52
static int naddr;   /* Number of addresses to process.  */
53
static char **addr;   /* Hex addresses to process.  */
54
55
static long symcount;
56
static asymbol **syms;    /* Symbol table.  */
57
58
static struct option long_options[] =
59
{
60
  {"addresses", no_argument, NULL, 'a'},
61
  {"basenames", no_argument, NULL, 's'},
62
  {"demangle", optional_argument, NULL, 'C'},
63
  {"exe", required_argument, NULL, 'e'},
64
  {"functions", no_argument, NULL, 'f'},
65
  {"inlines", no_argument, NULL, 'i'},
66
  {"pretty-print", no_argument, NULL, 'p'},
67
  {"recurse-limit", no_argument, NULL, 'R'},
68
  {"recursion-limit", no_argument, NULL, 'R'},  
69
  {"no-recurse-limit", no_argument, NULL, 'r'},
70
  {"no-recursion-limit", no_argument, NULL, 'r'},  
71
  {"section", required_argument, NULL, 'j'},
72
  {"target", required_argument, NULL, 'b'},
73
  {"help", no_argument, NULL, 'H'},
74
  {"version", no_argument, NULL, 'V'},
75
  {0, no_argument, 0, 0}
76
};
77
78
static void usage (FILE *, int);
79
static void slurp_symtab (bfd *);
80
static void find_address_in_section (bfd *, asection *, void *);
81
static void find_offset_in_section (bfd *, asection *);
82
static void translate_addresses (bfd *, asection *);
83

84
/* Print a usage message to STREAM and exit with STATUS.  */
85
86
static void
87
usage (FILE *stream, int status)
88
0
{
89
0
  fprintf (stream, _("Usage: %s [option(s)] [addr(s)]\n"), program_name);
90
0
  fprintf (stream, _(" Convert addresses into line number/file name pairs.\n"));
91
0
  fprintf (stream, _(" If no addresses are specified on the command line, they will be read from stdin\n"));
92
0
  fprintf (stream, _(" The options are:\n\
93
0
  @<file>                Read options from <file>\n\
94
0
  -a --addresses         Show addresses\n\
95
0
  -b --target=<bfdname>  Set the binary file format\n\
96
0
  -e --exe=<executable>  Set the input file name (default is a.out)\n\
97
0
  -i --inlines           Unwind inlined functions\n\
98
0
  -j --section=<name>    Read section-relative offsets instead of addresses\n\
99
0
  -p --pretty-print      Make the output easier to read for humans\n\
100
0
  -s --basenames         Strip directory names\n\
101
0
  -f --functions         Show function names\n\
102
0
  -C --demangle[=style]  Demangle function names\n\
103
0
  -R --recurse-limit     Enable a limit on recursion whilst demangling.  [Default]\n\
104
0
  -r --no-recurse-limit  Disable a limit on recursion whilst demangling\n\
105
0
  -h --help              Display this information\n\
106
0
  -v --version           Display the program's version\n\
107
0
\n"));
108
109
0
  list_supported_targets (program_name, stream);
110
0
  if (REPORT_BUGS_TO[0] && status == 0)
111
0
    fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
112
0
  exit (status);
113
0
}
114

115
/* Read in the symbol table.  */
116
117
static void
118
slurp_symtab (bfd *abfd)
119
14.7k
{
120
14.7k
  long storage;
121
14.7k
  bool dynamic = false;
122
123
14.7k
  if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0)
124
2.51k
    return;
125
126
12.1k
  storage = bfd_get_symtab_upper_bound (abfd);
127
12.1k
  if (storage == 0)
128
31
    {
129
31
      storage = bfd_get_dynamic_symtab_upper_bound (abfd);
130
31
      dynamic = true;
131
31
    }
132
12.1k
  if (storage < 0)
133
10.6k
    {
134
10.6k
      bfd_nonfatal (bfd_get_filename (abfd));
135
10.6k
      return;
136
10.6k
    }
137
138
1.56k
  syms = (asymbol **) xmalloc (storage);
139
1.56k
  if (dynamic)
140
0
    symcount = bfd_canonicalize_dynamic_symtab (abfd, syms);
141
1.56k
  else
142
1.56k
    symcount = bfd_canonicalize_symtab (abfd, syms);
143
1.56k
  if (symcount < 0)
144
159
    bfd_nonfatal (bfd_get_filename (abfd));
145
146
  /* If there are no symbols left after canonicalization and
147
     we have not tried the dynamic symbols then give them a go.  */
148
1.56k
  if (symcount == 0
149
1.56k
      && ! dynamic
150
1.56k
      && (storage = bfd_get_dynamic_symtab_upper_bound (abfd)) > 0)
151
127
    {
152
127
      free (syms);
153
127
      syms = xmalloc (storage);
154
127
      symcount = bfd_canonicalize_dynamic_symtab (abfd, syms);
155
127
    }
156
157
  /* PR 17512: file: 2a1d3b5b.
158
     Do not pretend that we have some symbols when we don't.  */
159
1.56k
  if (symcount <= 0)
160
260
    {
161
260
      free (syms);
162
260
      syms = NULL;
163
260
    }
164
1.56k
}
165

166
/* These global variables are used to pass information between
167
   translate_addresses and find_address_in_section.  */
168
169
static bfd_vma pc;
170
static const char *filename;
171
static const char *functionname;
172
static unsigned int line;
173
static unsigned int discriminator;
174
static bool found;
175
176
/* Look for an address in a section.  This is called via
177
   bfd_map_over_sections.  */
178
179
static void
180
find_address_in_section (bfd *abfd, asection *section,
181
       void *data ATTRIBUTE_UNUSED)
182
6.43M
{
183
6.43M
  bfd_vma vma;
184
6.43M
  bfd_size_type size;
185
186
6.43M
  if (found)
187
3.39M
    return;
188
189
3.03M
  if ((bfd_section_flags (section) & SEC_ALLOC) == 0)
190
877k
    return;
191
192
2.16M
  vma = bfd_section_vma (section);
193
2.16M
  if (pc < vma)
194
864k
    return;
195
196
1.29M
  size = bfd_section_size (section);
197
1.29M
  if (pc >= vma + size)
198
1.00M
    return;
199
200
290k
  found = bfd_find_nearest_line_discriminator (abfd, section, syms, pc - vma,
201
290k
                                               &filename, &functionname,
202
290k
                                               &line, &discriminator);
203
290k
}
204
205
/* Look for an offset in a section.  This is directly called.  */
206
207
static void
208
find_offset_in_section (bfd *abfd, asection *section)
209
0
{
210
0
  bfd_size_type size;
211
212
0
  if (found)
213
0
    return;
214
215
0
  if ((bfd_section_flags (section) & SEC_ALLOC) == 0)
216
0
    return;
217
218
0
  size = bfd_section_size (section);
219
0
  if (pc >= size)
220
0
    return;
221
222
0
  found = bfd_find_nearest_line_discriminator (abfd, section, syms, pc,
223
0
                                               &filename, &functionname,
224
0
                                               &line, &discriminator);
225
0
}
226
227
/* Lookup a symbol with offset in symbol table.  */
228
229
static bfd_vma
230
lookup_symbol (bfd *abfd, char *sym, size_t offset)
231
0
{
232
0
  long i;
233
234
0
  for (i = 0; i < symcount; i++)
235
0
    {
236
0
      if (!strcmp (syms[i]->name, sym))
237
0
  return syms[i]->value + offset + bfd_asymbol_section (syms[i])->vma;
238
0
    }
239
  /* Try again mangled */
240
0
  for (i = 0; i < symcount; i++)
241
0
    {
242
0
      char *d = bfd_demangle (abfd, syms[i]->name, demangle_flags);
243
0
      bool match = d && !strcmp (d, sym);
244
0
      free (d);
245
246
0
      if (match)
247
0
  return syms[i]->value + offset + bfd_asymbol_section (syms[i])->vma;
248
0
    }
249
0
  return 0;
250
0
}
251
252
/* Split an symbol+offset expression. adr is modified.  */
253
254
static bool
255
is_symbol (char *adr, char **symp, size_t *offset)
256
73.5k
{
257
73.5k
  char *end;
258
259
73.5k
  while (ISSPACE (*adr))
260
0
    adr++;
261
73.5k
  if (ISDIGIT (*adr) || *adr == 0)
262
44.1k
    return false;
263
  /* Could be either symbol or hex number. Check if it has +.  */
264
29.4k
  if (TOUPPER(*adr) >= 'A' && TOUPPER(*adr) <= 'F' && !strchr (adr, '+'))
265
29.4k
    return false;
266
267
0
  *symp = adr;
268
0
  while (*adr && !ISSPACE (*adr) && *adr != '+')
269
0
    adr++;
270
0
  end = adr;
271
0
  while (ISSPACE (*adr))
272
0
    adr++;
273
0
  *offset = 0;
274
0
  if (*adr == '+')
275
0
    {
276
0
      adr++;
277
0
      *offset = strtoul(adr, NULL, 0);
278
0
    }
279
0
  *end = 0;
280
0
  return true;
281
29.4k
}
282
283
/* Read hexadecimal or symbolic with offset addresses from stdin, translate into
284
   file_name:line_number and optionally function name.  */
285
286
static void
287
translate_addresses (bfd *abfd, asection *section)
288
14.7k
{
289
14.7k
  int read_stdin = (naddr == 0);
290
14.7k
  char *adr;
291
14.7k
  char addr_hex[100];
292
14.7k
  char *symp;
293
14.7k
  size_t offset;
294
295
14.7k
  for (;;)
296
88.2k
    {
297
88.2k
      if (read_stdin)
298
0
  {
299
0
    if (fgets (addr_hex, sizeof addr_hex, stdin) == NULL)
300
0
      break;
301
0
    adr = addr_hex;
302
0
  }
303
88.2k
      else
304
88.2k
  {
305
88.2k
    if (naddr <= 0)
306
14.7k
      break;
307
73.5k
    --naddr;
308
73.5k
    adr = *addr++;
309
73.5k
  }
310
311
73.5k
      if (is_symbol (adr, &symp, &offset))
312
0
        pc = lookup_symbol (abfd, symp, offset);
313
73.5k
      else
314
73.5k
        pc = bfd_scan_vma (adr, NULL, 16);
315
73.5k
      if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
316
7.53k
  {
317
7.53k
    const struct elf_backend_data *bed = get_elf_backend_data (abfd);
318
7.53k
    bfd_vma sign = (bfd_vma) 1 << (bed->s->arch_size - 1);
319
320
7.53k
    pc &= (sign << 1) - 1;
321
7.53k
    if (bed->sign_extend_vma)
322
3.37k
      pc = (pc ^ sign) - sign;
323
7.53k
  }
324
325
73.5k
      if (with_addresses)
326
0
        {
327
0
          printf ("0x");
328
0
          bfd_printf_vma (abfd, pc);
329
330
0
          if (pretty_print)
331
0
            printf (": ");
332
0
          else
333
0
            printf ("\n");
334
0
        }
335
336
73.5k
      found = false;
337
73.5k
      if (section)
338
0
  find_offset_in_section (abfd, section);
339
73.5k
      else
340
73.5k
  bfd_map_over_sections (abfd, find_address_in_section, NULL);
341
342
73.5k
      if (! found)
343
60.0k
  {
344
60.0k
    if (with_functions)
345
0
      {
346
0
        if (pretty_print)
347
0
    printf ("?? ");
348
0
        else
349
0
    printf ("??\n");
350
0
      }
351
60.0k
    printf ("??:0\n");
352
60.0k
  }
353
13.4k
      else
354
13.4k
  {
355
13.4k
    while (1)
356
13.4k
            {
357
13.4k
              if (with_functions)
358
0
                {
359
0
                  const char *name;
360
0
                  char *alloc = NULL;
361
362
0
                  name = functionname;
363
0
                  if (name == NULL || *name == '\0')
364
0
                    name = "??";
365
0
                  else if (do_demangle)
366
0
                    {
367
0
                      alloc = bfd_demangle (abfd, name, demangle_flags);
368
0
                      if (alloc != NULL)
369
0
                        name = alloc;
370
0
                    }
371
372
0
                  printf ("%s", name);
373
0
                  if (pretty_print)
374
        /* Note for translators:  This printf is used to join the
375
           function name just printed above to the line number/
376
           file name pair that is about to be printed below.  Eg:
377
378
             foo at 123:bar.c  */
379
0
                    printf (_(" at "));
380
0
                  else
381
0
                    printf ("\n");
382
383
0
      free (alloc);
384
0
                }
385
386
13.4k
              if (base_names && filename != NULL)
387
0
                {
388
0
                  char *h;
389
390
0
                  h = strrchr (filename, '/');
391
0
                  if (h != NULL)
392
0
                    filename = h + 1;
393
0
                }
394
395
13.4k
              printf ("%s:", filename ? filename : "??");
396
13.4k
        if (line != 0)
397
1.45k
                {
398
1.45k
                  if (discriminator != 0)
399
0
                    printf ("%u (discriminator %u)\n", line, discriminator);
400
1.45k
                  else
401
1.45k
                    printf ("%u\n", line);
402
1.45k
                }
403
12.0k
        else
404
12.0k
    printf ("?\n");
405
13.4k
              if (!unwind_inlines)
406
13.4k
                found = false;
407
0
              else
408
0
                found = bfd_find_inliner_info (abfd, &filename, &functionname,
409
13.4k
                 &line);
410
13.4k
              if (! found)
411
13.4k
                break;
412
0
              if (pretty_print)
413
    /* Note for translators: This printf is used to join the
414
       line number/file name pair that has just been printed with
415
       the line number/file name pair that is going to be printed
416
       by the next iteration of the while loop.  Eg:
417
418
         123:bar.c (inlined by) 456:main.c  */
419
0
                printf (_(" (inlined by) "));
420
0
            }
421
13.4k
  }
422
423
      /* fflush() is essential for using this command as a server
424
         child process that reads addresses from a pipe and responds
425
         with line number information, processing one address at a
426
         time.  */
427
73.5k
      fflush (stdout);
428
73.5k
    }
429
14.7k
}
430
431
/* Process a file.  Returns an exit value for main().  */
432
433
static int
434
process_file (const char *file_name, const char *section_name,
435
        const char *target)
436
26.7k
{
437
26.7k
  bfd *abfd;
438
26.7k
  asection *section;
439
26.7k
  char **matching;
440
441
26.7k
  if (get_file_size (file_name) < 1)
442
0
    return 1;
443
444
26.7k
  abfd = bfd_openr (file_name, target);
445
26.7k
  if (abfd == NULL)
446
0
    bfd_fatal (file_name);
447
448
  /* Decompress sections.  */
449
26.7k
  abfd->flags |= BFD_DECOMPRESS;
450
451
26.7k
  if (bfd_check_format (abfd, bfd_archive))
452
4.90k
    {
453
4.90k
      non_fatal (_("%s: cannot get addresses from archive"), file_name);
454
4.90k
      bfd_close (abfd);
455
4.90k
      return 1;
456
4.90k
    }
457
458
21.8k
  if (! bfd_check_format_matches (abfd, bfd_object, &matching))
459
7.15k
    {
460
7.15k
      bfd_nonfatal (bfd_get_filename (abfd));
461
7.15k
      if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
462
1.56k
  list_matching_formats (matching);
463
7.15k
      bfd_close (abfd);
464
7.15k
      return 1;
465
7.15k
    }
466
467
14.7k
  if (section_name != NULL)
468
0
    {
469
0
      section = bfd_get_section_by_name (abfd, section_name);
470
0
      if (section == NULL)
471
0
  {
472
0
    non_fatal (_("%s: cannot find section %s"), file_name, section_name);
473
0
    bfd_close (abfd);
474
0
    return 1;
475
0
  }
476
0
    }
477
14.7k
  else
478
14.7k
    section = NULL;
479
480
14.7k
  slurp_symtab (abfd);
481
482
14.7k
  translate_addresses (abfd, section);
483
484
14.7k
  free (syms);
485
14.7k
  syms = NULL;
486
487
14.7k
  bfd_close (abfd);
488
489
14.7k
  return 0;
490
14.7k
}
491

492
int
493
old_main32 (int argc, char **argv);
494
int old_main32 (int argc, char **argv)
495
0
{
496
0
  const char *file_name;
497
0
  const char *section_name;
498
0
  char *target;
499
0
  int c;
500
501
0
#ifdef HAVE_LC_MESSAGES
502
0
  setlocale (LC_MESSAGES, "");
503
0
#endif
504
0
  setlocale (LC_CTYPE, "");
505
0
  bindtextdomain (PACKAGE, LOCALEDIR);
506
0
  textdomain (PACKAGE);
507
508
0
  program_name = *argv;
509
0
  xmalloc_set_program_name (program_name);
510
0
  bfd_set_error_program_name (program_name);
511
512
0
  expandargv (&argc, &argv);
513
514
0
  if (bfd_init () != BFD_INIT_MAGIC)
515
0
    fatal (_("fatal error: libbfd ABI mismatch"));
516
0
  set_default_bfd_target ();
517
518
0
  file_name = NULL;
519
0
  section_name = NULL;
520
0
  target = NULL;
521
0
  while ((c = getopt_long (argc, argv, "ab:Ce:rRsfHhij:pVv", long_options, (int *) 0))
522
0
   != EOF)
523
0
    {
524
0
      switch (c)
525
0
  {
526
0
  case 0:
527
0
    break;   /* We've been given a long option.  */
528
0
  case 'a':
529
0
    with_addresses = true;
530
0
    break;
531
0
  case 'b':
532
0
    target = optarg;
533
0
    break;
534
0
  case 'C':
535
0
    do_demangle = true;
536
0
    if (optarg != NULL)
537
0
      {
538
0
        enum demangling_styles style;
539
540
0
        style = cplus_demangle_name_to_style (optarg);
541
0
        if (style == unknown_demangling)
542
0
    fatal (_("unknown demangling style `%s'"),
543
0
           optarg);
544
545
0
        cplus_demangle_set_style (style);
546
0
      }
547
0
    break;
548
0
  case 'r':
549
0
    demangle_flags |= DMGL_NO_RECURSE_LIMIT;
550
0
    break;
551
0
  case 'R':
552
0
    demangle_flags &= ~ DMGL_NO_RECURSE_LIMIT;
553
0
    break;
554
0
  case 'e':
555
0
    file_name = optarg;
556
0
    break;
557
0
  case 's':
558
0
    base_names = true;
559
0
    break;
560
0
  case 'f':
561
0
    with_functions = true;
562
0
    break;
563
0
        case 'p':
564
0
          pretty_print = true;
565
0
          break;
566
0
  case 'v':
567
0
  case 'V':
568
0
    print_version ("addr2line");
569
0
    break;
570
0
  case 'h':
571
0
  case 'H':
572
0
    usage (stdout, 0);
573
0
    break;
574
0
  case 'i':
575
0
    unwind_inlines = true;
576
0
    break;
577
0
  case 'j':
578
0
    section_name = optarg;
579
0
    break;
580
0
  default:
581
0
    usage (stderr, 1);
582
0
    break;
583
0
  }
584
0
    }
585
586
0
  if (file_name == NULL)
587
0
    file_name = "a.out";
588
589
0
  addr = argv + optind;
590
0
  naddr = argc - optind;
591
592
0
  return process_file (file_name, section_name, target);
593
0
}