/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 (¬es, 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 (¬es, 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 (¬es); |
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 (¬es)) |
329 | 0 | { |
330 | 0 | obstack_free (¬es, 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 (¬es)) |
379 | 8 | obstack_free (¬es, 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 | } |