Coverage Report

Created: 2026-07-25 10:20

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
650
#define STAB_SECTION_NAME ".stab"
42
#endif
43
44
#ifndef STAB_STRING_SECTION_NAME
45
650
#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
26
{
97
26
  unsigned int length;
98
26
  unsigned int retval;
99
26
  segT save_seg;
100
26
  subsegT save_subseg;
101
26
  char *p;
102
103
26
  if (! SEPARATE_STAB_SECTIONS)
104
0
    abort ();
105
106
26
  length = strlen (string);
107
108
26
  save_seg = now_seg;
109
26
  save_subseg = now_subseg;
110
111
26
  subseg_set (stabstr, 0);
112
113
26
  retval = seg_info (stabstr)->stabu.stab_string_size;
114
26
  if (retval <= 0)
115
26
    {
116
      /* Make sure the first string is empty.  */
117
26
      p = frag_more (1);
118
26
      *p = 0;
119
26
      retval = seg_info (stabstr)->stabu.stab_string_size = 1;
120
26
      bfd_set_section_flags (stabstr, SEC_READONLY | SEC_DEBUGGING);
121
26
    }
122
123
26
  if (length > 0)
124
22
    {       /* Ordinary case.  */
125
22
      p = frag_more (length + 1);
126
22
      strcpy (p, string);
127
128
22
      seg_info (stabstr)->stabu.stab_string_size += length + 1;
129
22
    }
130
4
  else
131
4
    retval = 0;
132
133
26
  subseg_set (save_seg, save_subseg);
134
135
26
  return retval;
136
26
}
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
1.41k
{
182
1.41k
  if (*input_line_pointer == ',')
183
764
    {
184
764
      input_line_pointer++;
185
764
      return true;
186
764
    }
187
649
  as_warn (_(".stab%c: missing comma"), what);
188
649
  ignore_rest_of_line ();
189
649
  return false;
190
1.41k
}
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
666
{
203
666
  const char *string;
204
666
  char *saved_string_obstack_end;
205
666
  int type;
206
666
  int other;
207
666
  int desc;
208
666
  segT stab, stabstr = NULL;
209
666
  segT saved_seg = now_seg;
210
666
  subsegT saved_subseg = now_subseg;
211
666
  fragS *saved_frag = frag_now;
212
666
  valueT dot = 0;
213
214
666
  if (SEPARATE_STAB_SECTIONS)
215
    /* Output the stab information in a separate section.  This is used
216
       at least for COFF and ELF.  */
217
666
    {
218
666
      dot = frag_now_fix ();
219
220
#ifdef md_flush_pending_output
221
      md_flush_pending_output ();
222
#endif
223
666
      stab = subseg_new (stab_secname, 0);
224
666
      stabstr = subseg_new (stabstr_secname, 0);
225
226
666
      if (freenames
227
16
    && stab->name != stab_secname
228
6
    && stabstr->name != stabstr_secname)
229
6
  obstack_free (&notes, stab_secname);
230
231
666
      subseg_set (stab, 0);
232
666
      if (!seg_info (stab)->stab_seen)
233
26
  {
234
26
    bfd_set_section_flags (stab,
235
26
         SEC_READONLY | SEC_RELOC | SEC_DEBUGGING);
236
26
#ifdef INIT_STAB_SECTION
237
26
    INIT_STAB_SECTION (stab, stabstr);
238
26
#endif
239
26
    seg_info (stab)->stab_seen = 1;
240
26
  }
241
666
    }
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
666
  saved_string_obstack_end = NULL;
254
666
  if (what != 's')
255
649
    string = "";
256
17
  else
257
17
    {
258
17
      int length;
259
260
17
      string = demand_copy_C_string (&length);
261
17
      if (string == NULL)
262
17
  {
263
17
    ignore_rest_of_line ();
264
17
    goto out2;
265
17
  }
266
      /* FIXME: We should probably find some other temporary storage
267
   for string, rather than leaking memory if someone else
268
   happens to use the notes obstack.  */
269
0
      saved_string_obstack_end = obstack_next_free (&notes);
270
0
      SKIP_WHITESPACE ();
271
0
      if (!eat_comma (what))
272
0
  goto out;
273
0
    }
274
275
649
  type = get_absolute_expression ();
276
649
  if (!eat_comma (what))
277
266
    goto out;
278
279
383
  other = get_absolute_expression ();
280
383
  if (!eat_comma (what))
281
2
    goto out;
282
283
381
  desc = get_absolute_expression ();
284
285
381
  if ((desc > 0xffff) || (desc < -0x8000))
286
    /* This could happen for example with a source file with a huge
287
       number of lines.  The only cure is to use a different debug
288
       format, probably DWARF.  */
289
1
    as_warn (_(".stab%c: description field '%x' too big, try a different debug format"),
290
1
       what, desc);
291
292
381
  if (what == 's' || what == 'n')
293
381
    {
294
381
      if (!eat_comma (what))
295
381
  goto out;
296
0
      SKIP_WHITESPACE ();
297
0
    }
298
299
0
#ifndef NO_LISTING
300
0
  if (listing)
301
0
    {
302
0
      switch (type)
303
0
  {
304
0
  case N_SLINE:
305
0
    listing_source_line (desc);
306
0
    break;
307
0
  case N_SO:
308
0
  case N_SOL:
309
0
    listing_source_file (string);
310
0
    break;
311
0
  }
312
0
    }
313
0
#endif /* ! NO_LISTING */
314
315
  /* We have now gathered the type, other, and desc information.  For
316
     .stabs or .stabn, input_line_pointer is now pointing at the
317
     value.  */
318
319
0
  if (SEPARATE_STAB_SECTIONS)
320
    /* Output the stab information in a separate section.  This is used
321
       at least for COFF and ELF.  */
322
0
    {
323
0
      unsigned int stroff;
324
0
      char *p;
325
326
0
      stroff = get_stab_string_offset (string, stabstr);
327
328
      /* Release the string, if nobody else has used the obstack.
329
   This must be done before creating symbols below, which uses
330
   the notes obstack.  */
331
0
      if (saved_string_obstack_end == obstack_next_free (&notes))
332
0
  {
333
0
    obstack_free (&notes, string);
334
0
    saved_string_obstack_end = NULL;
335
0
  }
336
337
      /* At least for now, stabs in a special stab section are always
338
   output as 12 byte blocks of information.  */
339
0
      p = frag_more (8);
340
0
      md_number_to_chars (p, stroff, 4);
341
0
      md_number_to_chars (p + 4, type, 1);
342
0
      md_number_to_chars (p + 5, other, 1);
343
0
      md_number_to_chars (p + 6, desc, 2);
344
345
0
      if (what == 's' || what == 'n')
346
0
  {
347
    /* Pick up the value from the input line.  */
348
0
    cons (4);
349
0
    input_line_pointer--;
350
0
  }
351
0
      else
352
0
  {
353
0
    symbolS *symbol;
354
0
    expressionS exp;
355
356
    /* Arrange for a value representing the current location.  */
357
0
    symbol = symbol_temp_new (saved_seg, saved_frag, dot);
358
359
0
    exp.X_op = O_symbol;
360
0
    exp.X_add_symbol = symbol;
361
0
    exp.X_add_number = 0;
362
363
0
    emit_expr (&exp, 4);
364
0
  }
365
366
#ifdef OBJ_PROCESS_STAB
367
      OBJ_PROCESS_STAB (what, string, type, other, desc);
368
#endif
369
0
    }
370
0
  else
371
0
    {
372
#ifdef OBJ_PROCESS_STAB
373
      OBJ_PROCESS_STAB (what, string, type, other, desc);
374
#else
375
0
      abort ();
376
0
#endif
377
0
    }
378
379
0
  demand_empty_rest_of_line ();
380
649
 out:
381
649
  if (saved_string_obstack_end == obstack_next_free (&notes))
382
0
    obstack_free (&notes, string);
383
666
 out2:
384
666
  subseg_set (saved_seg, saved_subseg);
385
666
}
386
387
/* Regular stab directive.  */
388
389
void
390
s_stab (int what)
391
650
{
392
650
  s_stab_generic (what, STAB_SECTION_NAME, STAB_STRING_SECTION_NAME, false);
393
650
}
394
395
/* "Extended stabs", used in Solaris only now.  */
396
397
void
398
s_xstab (int what)
399
268
{
400
268
  int length;
401
268
  char *stab_secname, *stabstr_secname;
402
403
268
  stab_secname = demand_copy_C_string (&length);
404
268
  if (stab_secname == NULL)
405
252
    {
406
252
      ignore_rest_of_line ();
407
252
      return;
408
252
    }
409
16
  SKIP_WHITESPACE ();
410
16
  if (*input_line_pointer == ',')
411
16
    {
412
16
      input_line_pointer++;
413
      /* To get the name of the stab string section, simply add
414
   "str" to the stab section name.  */
415
16
      stabstr_secname = notes_concat (stab_secname, "str", (char *) NULL);
416
16
      s_stab_generic (what, stab_secname, stabstr_secname, true);
417
16
    }
418
0
  else
419
0
    {
420
0
      as_bad (_("comma missing in .xstabs"));
421
0
      ignore_rest_of_line ();
422
0
    }
423
16
}
424
425
#ifdef S_SET_DESC
426
427
/* Frob invented at RMS' request. Set the n_desc of a symbol.  */
428
429
void
430
s_desc (int ignore ATTRIBUTE_UNUSED)
431
{
432
  char *name;
433
  char c;
434
  char *p;
435
  symbolS *symbolP;
436
  int temp;
437
438
  c = get_symbol_name (&name);
439
  p = input_line_pointer;
440
  restore_line_pointer (c);
441
  SKIP_WHITESPACE ();
442
  if (*input_line_pointer != ',')
443
    {
444
      *p = 0;
445
      as_bad (_("expected comma after \"%s\""), name);
446
      *p = c;
447
      ignore_rest_of_line ();
448
    }
449
  else
450
    {
451
      input_line_pointer++;
452
      temp = get_absolute_expression ();
453
      *p = 0;
454
      symbolP = symbol_find_or_make (name);
455
      *p = c;
456
      S_SET_DESC (symbolP, temp);
457
    }
458
  demand_empty_rest_of_line ();
459
}       /* s_desc() */
460
461
#endif /* defined (S_SET_DESC) */
462
463
/* Generate stabs debugging information to denote the main source file.  */
464
465
void
466
stabs_generate_asm_file (void)
467
0
{
468
0
  const char *file;
469
0
  unsigned int lineno;
470
471
0
  file = as_where (&lineno);
472
0
  if (use_gnu_debug_info_extensions)
473
0
    {
474
0
      char *dir;
475
0
      char *dir2;
476
477
0
      dir = remap_debug_filename (getpwd ());
478
0
      dir2 = concat (dir, "/", NULL);
479
0
      generate_asm_file (N_SO, dir2);
480
0
      free (dir2);
481
0
      free (dir);
482
0
    }
483
0
  generate_asm_file (N_SO, file);
484
0
}
485
486
/* Generate stabs debugging information to denote the source file.
487
   TYPE is one of N_SO, N_SOL.  */
488
489
static void
490
generate_asm_file (int type, const char *file)
491
0
{
492
0
  char sym[30];
493
0
  char *buf;
494
0
  const char *tmp = file;
495
0
  const char *file_endp = file + strlen (file);
496
0
  char *bufp;
497
498
0
  if (last_asm_file != NULL
499
0
      && filename_cmp (last_asm_file, file) == 0)
500
0
    return;
501
502
  /* Rather than try to do this in some efficient fashion, we just
503
     generate a string and then parse it again.  That lets us use the
504
     existing stabs hook, which expect to see a string, rather than
505
     inventing new ones.  */
506
0
  sprintf (sym, "%sF%d", FAKE_LABEL_NAME, file_label_count);
507
0
  ++file_label_count;
508
509
  /* Allocate enough space for the file name (possibly extended with
510
     doubled up backslashes), the symbol name, and the other characters
511
     that make up a stabs file directive.  */
512
0
  bufp = buf = XNEWVEC (char, 2 * strlen (file) + strlen (sym) + 12);
513
514
0
  *bufp++ = '"';
515
516
0
  while (tmp < file_endp)
517
0
    {
518
0
      const char *bslash = strchr (tmp, '\\');
519
0
      size_t len = bslash != NULL ? bslash - tmp + 1 : file_endp - tmp;
520
521
      /* Double all backslashes, since demand_copy_C_string (used by
522
   s_stab to extract the part in quotes) will try to replace them as
523
   escape sequences.  backslash may appear in a filespec.  */
524
0
      memcpy (bufp, tmp, len);
525
526
0
      tmp += len;
527
0
      bufp += len;
528
529
0
      if (bslash != NULL)
530
0
  *bufp++ = '\\';
531
0
    }
532
533
0
  sprintf (bufp, "\",%d,0,0,%s\n", type, sym);
534
535
0
  temp_ilp (buf);
536
0
  s_stab ('s');
537
0
  restore_ilp ();
538
539
0
  colon (sym);
540
541
0
  free (last_asm_file);
542
0
  last_asm_file = xstrdup (file);
543
544
0
  free (buf);
545
0
}
546
547
/* Generate stabs debugging information for the current line.  This is
548
   used to produce debugging information for an assembler file.  */
549
550
void
551
stabs_generate_asm_lineno (void)
552
0
{
553
0
  const char *file;
554
0
  unsigned int lineno;
555
0
  char *buf;
556
0
  char sym[30];
557
558
  /* Rather than try to do this in some efficient fashion, we just
559
     generate a string and then parse it again.  That lets us use the
560
     existing stabs hook, which expect to see a string, rather than
561
     inventing new ones.  */
562
563
0
  file = as_where (&lineno);
564
565
  /* Don't emit sequences of stabs for the same line.  */
566
0
  if (prev_line_file != NULL
567
0
      && filename_cmp (file, prev_line_file) == 0)
568
0
    {
569
0
      if (lineno == prev_lineno)
570
  /* Same file/line as last time.  */
571
0
  return;
572
0
    }
573
0
  else
574
0
    {
575
      /* Remember file/line for next time.  */
576
0
      free (prev_line_file);
577
0
      prev_line_file = xstrdup (file);
578
0
    }
579
580
0
  prev_lineno = lineno;
581
582
  /* Let the world know that we are in the middle of generating a
583
     piece of stabs line debugging information.  */
584
0
  outputting_stabs_line_debug = 1;
585
586
0
  generate_asm_file (N_SOL, file);
587
588
0
  sprintf (sym, "%sL%d", FAKE_LABEL_NAME, line_label_count);
589
0
  ++line_label_count;
590
591
0
  if (current_function_label)
592
0
    {
593
0
      buf = XNEWVEC (char, 100 + strlen (current_function_label));
594
0
      sprintf (buf, "%d,0,%d,%s-%s\n", N_SLINE, lineno,
595
0
         sym, current_function_label);
596
0
    }
597
0
  else
598
0
    {
599
0
      buf = XNEWVEC (char, 100);
600
0
      sprintf (buf, "%d,0,%d,%s\n", N_SLINE, lineno, sym);
601
0
    }
602
603
0
  temp_ilp (buf);
604
0
  s_stab ('n');
605
0
  restore_ilp ();
606
607
0
  colon (sym);
608
609
0
  outputting_stabs_line_debug = 0;
610
0
  free (buf);
611
0
}
612
613
/* Emit a function stab.
614
   All assembler functions are assumed to have return type `void'.  */
615
616
void
617
stabs_generate_asm_func (const char *funcname, const char *startlabname)
618
0
{
619
0
  char *buf;
620
0
  unsigned int lineno;
621
622
0
  if (! void_emitted_p)
623
0
    {
624
0
      temp_ilp ((char *) "\"void:t1=1\",128,0,0,0");
625
0
      s_stab ('s');
626
0
      restore_ilp ();
627
0
      void_emitted_p = true;
628
0
    }
629
630
0
  as_where (&lineno);
631
0
  buf = xasprintf ("\"%s:F1\",%d,0,%d,%s",
632
0
       funcname, N_FUN, lineno + 1, startlabname);
633
0
  temp_ilp (buf);
634
0
  s_stab ('s');
635
0
  restore_ilp ();
636
0
  free (buf);
637
638
0
  free ((char *) current_function_label);
639
0
  current_function_label = xstrdup (startlabname);
640
0
}
641
642
/* Emit a stab to record the end of a function.  */
643
644
void
645
stabs_generate_asm_endfunc (const char *funcname ATTRIBUTE_UNUSED,
646
          const char *startlabname)
647
0
{
648
0
  char *buf;
649
0
  char sym[30];
650
651
0
  sprintf (sym, "%sendfunc%d", FAKE_LABEL_NAME, endfunc_label_count);
652
0
  ++endfunc_label_count;
653
0
  colon (sym);
654
655
0
  buf = xasprintf ("\"\",%d,0,0,%s-%s", N_FUN, sym, startlabname);
656
0
  temp_ilp (buf);
657
0
  s_stab ('s');
658
0
  restore_ilp ();
659
0
  free (buf);
660
661
0
  free ((char *) current_function_label);
662
0
  current_function_label = NULL;
663
0
}
664
665
void
666
stabs_begin (void)
667
535
{
668
535
  current_function_label = NULL;
669
535
  last_asm_file = NULL;
670
535
  file_label_count = 0;
671
535
  line_label_count = 0;
672
535
  prev_lineno = -1u;
673
535
  prev_line_file = NULL;
674
535
  void_emitted_p = false;
675
535
  endfunc_label_count = 0;
676
535
}
677
678
void
679
stabs_end (void)
680
535
{
681
535
  if (!ENABLE_LEAK_CHECK)
682
0
    return;
683
535
  free ((char *) current_function_label);
684
535
  free (last_asm_file);
685
535
  free (prev_line_file);
686
535
}