Coverage Report

Created: 2025-06-24 06:45

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