/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 (¬es, 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 (¬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 | 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 (¬es); |
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 (¬es)) |
332 | 0 | { |
333 | 0 | obstack_free (¬es, 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 (¬es)) |
382 | 0 | obstack_free (¬es, 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 | } |