Coverage Report

Created: 2026-03-10 08:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/binutils-gdb/gas/stabs.c
Line
Count
Source
1
/* Generic stabs parsing for gas.
2
   Copyright (C) 1989-2026 Free Software Foundation, Inc.
3
4
   This file is part of GAS, the GNU Assembler.
5
6
   GAS is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as
8
   published by the Free Software Foundation; either version 3,
9
   or (at your option) any later version.
10
11
   GAS is distributed in the hope that it will be useful, but
12
   WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
14
   the GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with GAS; see the file COPYING.  If not, write to the Free
18
   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19
   02110-1301, USA.  */
20
21
#include "as.h"
22
#include "filenames.h"
23
#include "obstack.h"
24
#include "subsegs.h"
25
#include "ecoff.h"
26
27
/* We need this, despite the apparent object format dependency, since
28
   it defines stab types, which all object formats can use now.  */
29
30
#include "aout/stab_gnu.h"
31
32
/* Holds whether the assembler is generating stabs line debugging
33
   information or not.  Potentially used by md_cleanup function.  */
34
35
int outputting_stabs_line_debug = 0;
36
37
static void generate_asm_file (int, const char *);
38
39
/* Allow backends to override the names used for the stab sections.  */
40
#ifndef STAB_SECTION_NAME
41
262
#define STAB_SECTION_NAME ".stab"
42
#endif
43
44
#ifndef STAB_STRING_SECTION_NAME
45
262
#define STAB_STRING_SECTION_NAME ".stabstr"
46
#endif
47
48
/* Label at start of current function if we're in the middle of a
49
   .func function, in which case stabs_generate_asm_lineno emits
50
   function relative line number stabs.  Otherwise it emits line
51
   number stabs with absolute addresses.  Note that both cases only
52
   apply to assembler code assembled with -gstabs.  */
53
static const char *current_function_label;
54
55
/* State used by generate_asm_file.  */
56
static char *last_asm_file;
57
static int file_label_count;
58
59
/* State used by stabs_generate_asm_lineno.  */
60
static int line_label_count;
61
static unsigned int prev_lineno;
62
static char *prev_line_file;
63
64
/* State used by stabs_generate_asm_func.  */
65
static bool void_emitted_p;
66
67
/* State used by stabs_generate_asm_endfunc.  */
68
static int endfunc_label_count;
69
70
/*
71
 * Handle .stabX directives, which used to be open-coded.
72
 * So much creeping featurism overloaded the semantics that we decided
73
 * to put all .stabX thinking in one place. Here.
74
 *
75
 * We try to make any .stabX directive legal. Other people's AS will often
76
 * do assembly-time consistency checks: eg assigning meaning to n_type bits
77
 * and "protecting" you from setting them to certain values. (They also zero
78
 * certain bits before emitting symbols. Tut tut.)
79
 *
80
 * If an expression is not absolute we either gripe or use the relocation
81
 * information. Other people's assemblers silently forget information they
82
 * don't need and invent information they need that you didn't supply.
83
 */
84
85
/*
86
 * Build a string dictionary entry for a .stabX symbol.
87
 * The symbol is added to the .<secname>str section.
88
 */
89
90
#ifndef SEPARATE_STAB_SECTIONS
91
#define SEPARATE_STAB_SECTIONS 0
92
#endif
93
94
unsigned int
95
get_stab_string_offset (const char *string, segT stabstr)
96
8
{
97
8
  unsigned int length;
98
8
  unsigned int retval;
99
8
  segT save_seg;
100
8
  subsegT save_subseg;
101
8
  char *p;
102
103
8
  if (! SEPARATE_STAB_SECTIONS)
104
0
    abort ();
105
106
8
  length = strlen (string);
107
108
8
  save_seg = now_seg;
109
8
  save_subseg = now_subseg;
110
111
8
  subseg_set (stabstr, 0);
112
113
8
  retval = seg_info (stabstr)->stabu.stab_string_size;
114
8
  if (retval <= 0)
115
7
    {
116
      /* Make sure the first string is empty.  */
117
7
      p = frag_more (1);
118
7
      *p = 0;
119
7
      retval = seg_info (stabstr)->stabu.stab_string_size = 1;
120
7
      bfd_set_section_flags (stabstr, SEC_READONLY | SEC_DEBUGGING);
121
7
    }
122
123
8
  if (length > 0)
124
8
    {       /* Ordinary case.  */
125
8
      p = frag_more (length + 1);
126
8
      strcpy (p, string);
127
128
8
      seg_info (stabstr)->stabu.stab_string_size += length + 1;
129
8
    }
130
0
  else
131
0
    retval = 0;
132
133
8
  subseg_set (save_seg, save_subseg);
134
135
8
  return retval;
136
8
}
137
138
#ifdef AOUT_STABS
139
#ifndef OBJ_PROCESS_STAB
140
#define OBJ_PROCESS_STAB(W,S,T,O,D) aout_process_stab(W,S,T,O,D)
141
#endif
142
143
/* Here instead of obj-aout.c because other formats use it too.  */
144
void
145
aout_process_stab (int what, const char *string, int type, int other, int desc)
146
{
147
  /* Put the stab information in the symbol table.  */
148
  symbolS *symbol;
149
150
  /* Create the symbol now, but only insert it into the symbol chain
151
     after any symbols mentioned in the value expression get into the
152
     symbol chain.  This is to avoid "continuation symbols" (where one
153
     ends in "\" and the debug info is continued in the next .stabs
154
     directive) from being separated by other random symbols.  */
155
  symbol = symbol_create (string, undefined_section, &zero_address_frag, 0);
156
  if (what == 's' || what == 'n')
157
    {
158
      /* Pick up the value from the input line.  */
159
      pseudo_set (symbol);
160
    }
161
  else
162
    {
163
      /* .stabd sets the name to NULL.  Why?  */
164
      S_SET_NAME (symbol, NULL);
165
      symbol_set_frag (symbol, frag_now);
166
      S_SET_VALUE (symbol, frag_now_fix ());
167
    }
168
169
  symbol_append (symbol, symbol_lastP, &symbol_rootP, &symbol_lastP);
170
171
  symbol_get_bfdsym (symbol)->flags |= BSF_DEBUGGING;
172
173
  S_SET_TYPE (symbol, type);
174
  S_SET_OTHER (symbol, other);
175
  S_SET_DESC (symbol, desc);
176
}
177
#endif
178
179
static bool
180
eat_comma (int what)
181
777
{
182
777
  if (*input_line_pointer == ',')
183
516
    {
184
516
      input_line_pointer++;
185
516
      return true;
186
516
    }
187
261
  as_warn (_(".stab%c: missing comma"), what);
188
261
  ignore_rest_of_line ();
189
261
  return false;
190
777
}
191
192
/* This can handle different kinds of stabs (s,n,d) and different
193
   kinds of stab sections.  If FREENAMES is true, then STAB_SECNAME
194
   and STABSTR_SECNAME are allocated in that order on the notes
195
   obstack and will be freed if possible.  */
196
197
static void
198
s_stab_generic (int what,
199
    const char *stab_secname,
200
    const char *stabstr_secname,
201
    bool freenames)
202
262
{
203
262
  const char *string;
204
262
  char *saved_string_obstack_end;
205
262
  int type;
206
262
  int other;
207
262
  int desc;
208
262
  segT stab, stabstr = NULL;
209
262
  segT saved_seg = now_seg;
210
262
  subsegT saved_subseg = now_subseg;
211
262
  fragS *saved_frag = frag_now;
212
262
  valueT dot = 0;
213
214
262
  if (SEPARATE_STAB_SECTIONS)
215
    /* Output the stab information in a separate section.  This is used
216
       at least for COFF and ELF.  */
217
262
    {
218
262
      dot = frag_now_fix ();
219
220
#ifdef md_flush_pending_output
221
      md_flush_pending_output ();
222
#endif
223
262
      stab = subseg_new (stab_secname, 0);
224
262
      stabstr = subseg_new (stabstr_secname, 0);
225
226
262
      if (freenames
227
0
    && stab->name != stab_secname
228
0
    && stabstr->name != stabstr_secname)
229
0
  obstack_free (&notes, stab_secname);
230
231
262
      subseg_set (stab, 0);
232
262
      if (!seg_info (stab)->stab_seen)
233
7
  {
234
7
    bfd_set_section_flags (stab,
235
7
         SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
236
7
#ifdef INIT_STAB_SECTION
237
7
    INIT_STAB_SECTION (stab, stabstr);
238
7
#endif
239
7
    seg_info (stab)->stab_seen = 1;
240
7
  }
241
262
    }
242
0
  else if (freenames)
243
0
    obstack_free (&notes, stab_secname);
244
245
  /* The general format is:
246
     .stabs "STRING",TYPE,OTHER,DESC,VALUE
247
     .stabn TYPE,OTHER,DESC,VALUE
248
     .stabd TYPE,OTHER,DESC
249
     At this point input_line_pointer points after the pseudo-op and
250
     any trailing whitespace.  The argument what is one of 's', 'n' or
251
     'd' indicating which type of .stab this is.  */
252
253
262
  saved_string_obstack_end = NULL;
254
262
  if (what != 's')
255
253
    string = "";
256
9
  else
257
9
    {
258
9
      int length;
259
260
9
      string = demand_copy_C_string (&length);
261
9
      if (string == NULL)
262
0
  goto out2;
263
      /* FIXME: We should probably find some other temporary storage
264
   for string, rather than leaking memory if someone else
265
   happens to use the notes obstack.  */
266
9
      saved_string_obstack_end = obstack_next_free (&notes);
267
9
      SKIP_WHITESPACE ();
268
9
      if (!eat_comma (what))
269
0
  goto out;
270
9
    }
271
272
262
  type = get_absolute_expression ();
273
262
  if (!eat_comma (what))
274
8
    goto out;
275
276
254
  other = get_absolute_expression ();
277
254
  if (!eat_comma (what))
278
2
    goto out;
279
280
252
  desc = get_absolute_expression ();
281
282
252
  if ((desc > 0xffff) || (desc < -0x8000))
283
    /* This could happen for example with a source file with a huge
284
       number of lines.  The only cure is to use a different debug
285
       format, probably DWARF.  */
286
0
    as_warn (_(".stab%c: description field '%x' too big, try a different debug format"),
287
0
       what, desc);
288
289
252
  if (what == 's' || what == 'n')
290
252
    {
291
252
      if (!eat_comma (what))
292
251
  goto out;
293
1
      SKIP_WHITESPACE ();
294
1
    }
295
296
1
#ifndef NO_LISTING
297
1
  if (listing)
298
0
    {
299
0
      switch (type)
300
0
  {
301
0
  case N_SLINE:
302
0
    listing_source_line (desc);
303
0
    break;
304
0
  case N_SO:
305
0
  case N_SOL:
306
0
    listing_source_file (string);
307
0
    break;
308
0
  }
309
0
    }
310
1
#endif /* ! NO_LISTING */
311
312
  /* We have now gathered the type, other, and desc information.  For
313
     .stabs or .stabn, input_line_pointer is now pointing at the
314
     value.  */
315
316
1
  if (SEPARATE_STAB_SECTIONS)
317
    /* Output the stab information in a separate section.  This is used
318
       at least for COFF and ELF.  */
319
1
    {
320
1
      unsigned int stroff;
321
1
      char *p;
322
323
1
      stroff = get_stab_string_offset (string, stabstr);
324
325
      /* Release the string, if nobody else has used the obstack.
326
   This must be done before creating symbols below, which uses
327
   the notes obstack.  */
328
1
      if (saved_string_obstack_end == obstack_next_free (&notes))
329
0
  {
330
0
    obstack_free (&notes, string);
331
0
    saved_string_obstack_end = NULL;
332
0
  }
333
334
      /* At least for now, stabs in a special stab section are always
335
   output as 12 byte blocks of information.  */
336
1
      p = frag_more (8);
337
1
      md_number_to_chars (p, stroff, 4);
338
1
      md_number_to_chars (p + 4, type, 1);
339
1
      md_number_to_chars (p + 5, other, 1);
340
1
      md_number_to_chars (p + 6, desc, 2);
341
342
1
      if (what == 's' || what == 'n')
343
1
  {
344
    /* Pick up the value from the input line.  */
345
1
    cons (4);
346
1
    input_line_pointer--;
347
1
  }
348
0
      else
349
0
  {
350
0
    symbolS *symbol;
351
0
    expressionS exp;
352
353
    /* Arrange for a value representing the current location.  */
354
0
    symbol = symbol_temp_new (saved_seg, saved_frag, dot);
355
356
0
    exp.X_op = O_symbol;
357
0
    exp.X_add_symbol = symbol;
358
0
    exp.X_add_number = 0;
359
360
0
    emit_expr (&exp, 4);
361
0
  }
362
363
#ifdef OBJ_PROCESS_STAB
364
      OBJ_PROCESS_STAB (what, string, type, other, desc);
365
#endif
366
1
    }
367
0
  else
368
0
    {
369
#ifdef OBJ_PROCESS_STAB
370
      OBJ_PROCESS_STAB (what, string, type, other, desc);
371
#else
372
0
      abort ();
373
0
#endif
374
0
    }
375
376
1
  demand_empty_rest_of_line ();
377
262
 out:
378
262
  if (saved_string_obstack_end == obstack_next_free (&notes))
379
8
    obstack_free (&notes, string);
380
262
 out2:
381
262
  subseg_set (saved_seg, saved_subseg);
382
262
}
383
384
/* Regular stab directive.  */
385
386
void
387
s_stab (int what)
388
262
{
389
262
  s_stab_generic (what, STAB_SECTION_NAME, STAB_STRING_SECTION_NAME, false);
390
262
}
391
392
/* "Extended stabs", used in Solaris only now.  */
393
394
void
395
s_xstab (int what)
396
250
{
397
250
  int length;
398
250
  char *stab_secname, *stabstr_secname;
399
400
250
  stab_secname = demand_copy_C_string (&length);
401
250
  if (stab_secname == NULL)
402
    /* as_bad error has been reported.  */
403
250
    return;
404
0
  SKIP_WHITESPACE ();
405
0
  if (*input_line_pointer == ',')
406
0
    {
407
0
      input_line_pointer++;
408
      /* To get the name of the stab string section, simply add
409
   "str" to the stab section name.  */
410
0
      stabstr_secname = notes_concat (stab_secname, "str", (char *) NULL);
411
0
      s_stab_generic (what, stab_secname, stabstr_secname, true);
412
0
    }
413
0
  else
414
0
    {
415
0
      as_bad (_("comma missing in .xstabs"));
416
0
      ignore_rest_of_line ();
417
0
    }
418
0
}
419
420
#ifdef S_SET_DESC
421
422
/* Frob invented at RMS' request. Set the n_desc of a symbol.  */
423
424
void
425
s_desc (int ignore ATTRIBUTE_UNUSED)
426
{
427
  char *name;
428
  char c;
429
  char *p;
430
  symbolS *symbolP;
431
  int temp;
432
433
  c = get_symbol_name (&name);
434
  p = input_line_pointer;
435
  restore_line_pointer (c);
436
  SKIP_WHITESPACE ();
437
  if (*input_line_pointer != ',')
438
    {
439
      *p = 0;
440
      as_bad (_("expected comma after \"%s\""), name);
441
      *p = c;
442
      ignore_rest_of_line ();
443
    }
444
  else
445
    {
446
      input_line_pointer++;
447
      temp = get_absolute_expression ();
448
      *p = 0;
449
      symbolP = symbol_find_or_make (name);
450
      *p = c;
451
      S_SET_DESC (symbolP, temp);
452
    }
453
  demand_empty_rest_of_line ();
454
}       /* s_desc() */
455
456
#endif /* defined (S_SET_DESC) */
457
458
/* Generate stabs debugging information to denote the main source file.  */
459
460
void
461
stabs_generate_asm_file (void)
462
0
{
463
0
  const char *file;
464
0
  unsigned int lineno;
465
466
0
  file = as_where (&lineno);
467
0
  if (use_gnu_debug_info_extensions)
468
0
    {
469
0
      char *dir;
470
0
      char *dir2;
471
472
0
      dir = remap_debug_filename (getpwd ());
473
0
      dir2 = concat (dir, "/", NULL);
474
0
      generate_asm_file (N_SO, dir2);
475
0
      free (dir2);
476
0
      free (dir);
477
0
    }
478
0
  generate_asm_file (N_SO, file);
479
0
}
480
481
/* Generate stabs debugging information to denote the source file.
482
   TYPE is one of N_SO, N_SOL.  */
483
484
static void
485
generate_asm_file (int type, const char *file)
486
0
{
487
0
  char sym[30];
488
0
  char *buf;
489
0
  const char *tmp = file;
490
0
  const char *file_endp = file + strlen (file);
491
0
  char *bufp;
492
493
0
  if (last_asm_file != NULL
494
0
      && filename_cmp (last_asm_file, file) == 0)
495
0
    return;
496
497
  /* Rather than try to do this in some efficient fashion, we just
498
     generate a string and then parse it again.  That lets us use the
499
     existing stabs hook, which expect to see a string, rather than
500
     inventing new ones.  */
501
0
  sprintf (sym, "%sF%d", FAKE_LABEL_NAME, file_label_count);
502
0
  ++file_label_count;
503
504
  /* Allocate enough space for the file name (possibly extended with
505
     doubled up backslashes), the symbol name, and the other characters
506
     that make up a stabs file directive.  */
507
0
  bufp = buf = XNEWVEC (char, 2 * strlen (file) + strlen (sym) + 12);
508
509
0
  *bufp++ = '"';
510
511
0
  while (tmp < file_endp)
512
0
    {
513
0
      const char *bslash = strchr (tmp, '\\');
514
0
      size_t len = bslash != NULL ? bslash - tmp + 1 : file_endp - tmp;
515
516
      /* Double all backslashes, since demand_copy_C_string (used by
517
   s_stab to extract the part in quotes) will try to replace them as
518
   escape sequences.  backslash may appear in a filespec.  */
519
0
      memcpy (bufp, tmp, len);
520
521
0
      tmp += len;
522
0
      bufp += len;
523
524
0
      if (bslash != NULL)
525
0
  *bufp++ = '\\';
526
0
    }
527
528
0
  sprintf (bufp, "\",%d,0,0,%s\n", type, sym);
529
530
0
  temp_ilp (buf);
531
0
  s_stab ('s');
532
0
  restore_ilp ();
533
534
0
  colon (sym);
535
536
0
  free (last_asm_file);
537
0
  last_asm_file = xstrdup (file);
538
539
0
  free (buf);
540
0
}
541
542
/* Generate stabs debugging information for the current line.  This is
543
   used to produce debugging information for an assembler file.  */
544
545
void
546
stabs_generate_asm_lineno (void)
547
0
{
548
0
  const char *file;
549
0
  unsigned int lineno;
550
0
  char *buf;
551
0
  char sym[30];
552
553
  /* Rather than try to do this in some efficient fashion, we just
554
     generate a string and then parse it again.  That lets us use the
555
     existing stabs hook, which expect to see a string, rather than
556
     inventing new ones.  */
557
558
0
  file = as_where (&lineno);
559
560
  /* Don't emit sequences of stabs for the same line.  */
561
0
  if (prev_line_file != NULL
562
0
      && filename_cmp (file, prev_line_file) == 0)
563
0
    {
564
0
      if (lineno == prev_lineno)
565
  /* Same file/line as last time.  */
566
0
  return;
567
0
    }
568
0
  else
569
0
    {
570
      /* Remember file/line for next time.  */
571
0
      free (prev_line_file);
572
0
      prev_line_file = xstrdup (file);
573
0
    }
574
575
0
  prev_lineno = lineno;
576
577
  /* Let the world know that we are in the middle of generating a
578
     piece of stabs line debugging information.  */
579
0
  outputting_stabs_line_debug = 1;
580
581
0
  generate_asm_file (N_SOL, file);
582
583
0
  sprintf (sym, "%sL%d", FAKE_LABEL_NAME, line_label_count);
584
0
  ++line_label_count;
585
586
0
  if (current_function_label)
587
0
    {
588
0
      buf = XNEWVEC (char, 100 + strlen (current_function_label));
589
0
      sprintf (buf, "%d,0,%d,%s-%s\n", N_SLINE, lineno,
590
0
         sym, current_function_label);
591
0
    }
592
0
  else
593
0
    {
594
0
      buf = XNEWVEC (char, 100);
595
0
      sprintf (buf, "%d,0,%d,%s\n", N_SLINE, lineno, sym);
596
0
    }
597
598
0
  temp_ilp (buf);
599
0
  s_stab ('n');
600
0
  restore_ilp ();
601
602
0
  colon (sym);
603
604
0
  outputting_stabs_line_debug = 0;
605
0
  free (buf);
606
0
}
607
608
/* Emit a function stab.
609
   All assembler functions are assumed to have return type `void'.  */
610
611
void
612
stabs_generate_asm_func (const char *funcname, const char *startlabname)
613
0
{
614
0
  char *buf;
615
0
  unsigned int lineno;
616
617
0
  if (! void_emitted_p)
618
0
    {
619
0
      temp_ilp ((char *) "\"void:t1=1\",128,0,0,0");
620
0
      s_stab ('s');
621
0
      restore_ilp ();
622
0
      void_emitted_p = true;
623
0
    }
624
625
0
  as_where (&lineno);
626
0
  buf = xasprintf ("\"%s:F1\",%d,0,%d,%s",
627
0
       funcname, N_FUN, lineno + 1, startlabname);
628
0
  temp_ilp (buf);
629
0
  s_stab ('s');
630
0
  restore_ilp ();
631
0
  free (buf);
632
633
0
  free ((char *) current_function_label);
634
0
  current_function_label = xstrdup (startlabname);
635
0
}
636
637
/* Emit a stab to record the end of a function.  */
638
639
void
640
stabs_generate_asm_endfunc (const char *funcname ATTRIBUTE_UNUSED,
641
          const char *startlabname)
642
0
{
643
0
  char *buf;
644
0
  char sym[30];
645
646
0
  sprintf (sym, "%sendfunc%d", FAKE_LABEL_NAME, endfunc_label_count);
647
0
  ++endfunc_label_count;
648
0
  colon (sym);
649
650
0
  buf = xasprintf ("\"\",%d,0,0,%s-%s", N_FUN, sym, startlabname);
651
0
  temp_ilp (buf);
652
0
  s_stab ('s');
653
0
  restore_ilp ();
654
0
  free (buf);
655
656
0
  free ((char *) current_function_label);
657
0
  current_function_label = NULL;
658
0
}
659
660
void
661
stabs_begin (void)
662
207
{
663
207
  current_function_label = NULL;
664
207
  last_asm_file = NULL;
665
207
  file_label_count = 0;
666
207
  line_label_count = 0;
667
207
  prev_lineno = -1u;
668
207
  prev_line_file = NULL;
669
207
  void_emitted_p = false;
670
207
  endfunc_label_count = 0;
671
207
}
672
673
void
674
stabs_end (void)
675
207
{
676
207
  if (!ENABLE_LEAK_CHECK)
677
0
    return;
678
207
  free ((char *) current_function_label);
679
207
  free (last_asm_file);
680
207
  free (prev_line_file);
681
207
}