/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 (¬es, 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 (¬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 | 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 (¬es); |
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 (¬es)) |
353 | 0 | { |
354 | 0 | obstack_free (¬es, 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 (¬es)) |
403 | 0 | obstack_free (¬es, 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 | } |