/src/binutils-gdb/gas/stabs.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Generic stabs parsing for gas. |
2 | | Copyright (C) 1989-2023 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 | 837 | #define STAB_SECTION_NAME ".stab" |
42 | | #endif |
43 | | |
44 | | #ifndef STAB_STRING_SECTION_NAME |
45 | 837 | #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 | | /* Current stab section when SEPARATE_STAB_SECTIONS. */ |
56 | | static segT cached_sec; |
57 | | |
58 | | /* State used by generate_asm_file. */ |
59 | | static char *last_asm_file; |
60 | | static int file_label_count; |
61 | | |
62 | | /* State used by stabs_generate_asm_lineno. */ |
63 | | static int line_label_count; |
64 | | static unsigned int prev_lineno; |
65 | | static char *prev_line_file; |
66 | | |
67 | | /* State used by stabs_generate_asm_func. */ |
68 | | static bool void_emitted_p; |
69 | | |
70 | | /* State used by stabs_generate_asm_endfunc. */ |
71 | | static int endfunc_label_count; |
72 | | |
73 | | /* |
74 | | * Handle .stabX directives, which used to be open-coded. |
75 | | * So much creeping featurism overloaded the semantics that we decided |
76 | | * to put all .stabX thinking in one place. Here. |
77 | | * |
78 | | * We try to make any .stabX directive legal. Other people's AS will often |
79 | | * do assembly-time consistency checks: eg assigning meaning to n_type bits |
80 | | * and "protecting" you from setting them to certain values. (They also zero |
81 | | * certain bits before emitting symbols. Tut tut.) |
82 | | * |
83 | | * If an expression is not absolute we either gripe or use the relocation |
84 | | * information. Other people's assemblers silently forget information they |
85 | | * don't need and invent information they need that you didn't supply. |
86 | | */ |
87 | | |
88 | | /* |
89 | | * Build a string dictionary entry for a .stabX symbol. |
90 | | * The symbol is added to the .<secname>str section. |
91 | | */ |
92 | | |
93 | | #ifndef SEPARATE_STAB_SECTIONS |
94 | | #define SEPARATE_STAB_SECTIONS 0 |
95 | | #endif |
96 | | |
97 | | unsigned int |
98 | | get_stab_string_offset (const char *string, const char *stabstr_secname, |
99 | | bool free_stabstr_secname) |
100 | 323 | { |
101 | 323 | unsigned int length; |
102 | 323 | unsigned int retval; |
103 | 323 | segT save_seg; |
104 | 323 | subsegT save_subseg; |
105 | 323 | segT seg; |
106 | 323 | char *p; |
107 | | |
108 | 323 | if (! SEPARATE_STAB_SECTIONS) |
109 | 0 | abort (); |
110 | | |
111 | 323 | length = strlen (string); |
112 | | |
113 | 323 | save_seg = now_seg; |
114 | 323 | save_subseg = now_subseg; |
115 | | |
116 | | /* Create the stab string section, if it doesn't already exist. */ |
117 | 323 | seg = subseg_new (stabstr_secname, 0); |
118 | 323 | if (free_stabstr_secname && seg->name != stabstr_secname) |
119 | 0 | free ((char *) stabstr_secname); |
120 | | |
121 | 323 | retval = seg_info (seg)->stabu.stab_string_size; |
122 | 323 | if (retval <= 0) |
123 | 61 | { |
124 | | /* Make sure the first string is empty. */ |
125 | 61 | p = frag_more (1); |
126 | 61 | *p = 0; |
127 | 61 | retval = seg_info (seg)->stabu.stab_string_size = 1; |
128 | 61 | bfd_set_section_flags (seg, SEC_READONLY | SEC_DEBUGGING); |
129 | 61 | } |
130 | | |
131 | 323 | if (length > 0) |
132 | 60 | { /* Ordinary case. */ |
133 | 60 | p = frag_more (length + 1); |
134 | 60 | strcpy (p, string); |
135 | | |
136 | 60 | seg_info (seg)->stabu.stab_string_size += length + 1; |
137 | 60 | } |
138 | 263 | else |
139 | 263 | retval = 0; |
140 | | |
141 | 323 | subseg_set (save_seg, save_subseg); |
142 | | |
143 | 323 | return retval; |
144 | 323 | } |
145 | | |
146 | | #ifdef AOUT_STABS |
147 | | #ifndef OBJ_PROCESS_STAB |
148 | | #define OBJ_PROCESS_STAB(SEG,W,S,T,O,D) aout_process_stab(W,S,T,O,D) |
149 | | #endif |
150 | | |
151 | | /* Here instead of obj-aout.c because other formats use it too. */ |
152 | | void |
153 | | aout_process_stab (int what, const char *string, int type, int other, int desc) |
154 | | { |
155 | | /* Put the stab information in the symbol table. */ |
156 | | symbolS *symbol; |
157 | | |
158 | | /* Create the symbol now, but only insert it into the symbol chain |
159 | | after any symbols mentioned in the value expression get into the |
160 | | symbol chain. This is to avoid "continuation symbols" (where one |
161 | | ends in "\" and the debug info is continued in the next .stabs |
162 | | directive) from being separated by other random symbols. */ |
163 | | symbol = symbol_create (string, undefined_section, &zero_address_frag, 0); |
164 | | if (what == 's' || what == 'n') |
165 | | { |
166 | | /* Pick up the value from the input line. */ |
167 | | pseudo_set (symbol); |
168 | | } |
169 | | else |
170 | | { |
171 | | /* .stabd sets the name to NULL. Why? */ |
172 | | S_SET_NAME (symbol, NULL); |
173 | | symbol_set_frag (symbol, frag_now); |
174 | | S_SET_VALUE (symbol, (valueT) frag_now_fix ()); |
175 | | } |
176 | | |
177 | | symbol_append (symbol, symbol_lastP, &symbol_rootP, &symbol_lastP); |
178 | | |
179 | | symbol_get_bfdsym (symbol)->flags |= BSF_DEBUGGING; |
180 | | |
181 | | S_SET_TYPE (symbol, type); |
182 | | S_SET_OTHER (symbol, other); |
183 | | S_SET_DESC (symbol, desc); |
184 | | } |
185 | | #endif |
186 | | |
187 | | /* This can handle different kinds of stabs (s,n,d) and different |
188 | | kinds of stab sections. If STAB_SECNAME_OBSTACK_END is non-NULL, |
189 | | then STAB_SECNAME and STABSTR_SECNAME will be freed if possible |
190 | | before this function returns (the former by obstack_free). */ |
191 | | |
192 | | static void |
193 | | s_stab_generic (int what, |
194 | | const char *stab_secname, |
195 | | const char *stabstr_secname, |
196 | | const char *stab_secname_obstack_end) |
197 | 837 | { |
198 | 837 | long longint; |
199 | 837 | const char *string; |
200 | 837 | char *saved_string_obstack_end; |
201 | 837 | int type; |
202 | 837 | int other; |
203 | 837 | int desc; |
204 | | |
205 | | /* The general format is: |
206 | | .stabs "STRING",TYPE,OTHER,DESC,VALUE |
207 | | .stabn TYPE,OTHER,DESC,VALUE |
208 | | .stabd TYPE,OTHER,DESC |
209 | | At this point input_line_pointer points after the pseudo-op and |
210 | | any trailing whitespace. The argument what is one of 's', 'n' or |
211 | | 'd' indicating which type of .stab this is. */ |
212 | | |
213 | 837 | if (what != 's') |
214 | 808 | { |
215 | 808 | string = ""; |
216 | 808 | saved_string_obstack_end = 0; |
217 | 808 | } |
218 | 29 | else |
219 | 29 | { |
220 | 29 | int length; |
221 | | |
222 | 29 | string = demand_copy_C_string (&length); |
223 | 29 | if (string == NULL) |
224 | 29 | { |
225 | 29 | as_warn (_(".stab%c: missing string"), what); |
226 | 29 | ignore_rest_of_line (); |
227 | 29 | return; |
228 | 29 | } |
229 | | /* FIXME: We should probably find some other temporary storage |
230 | | for string, rather than leaking memory if someone else |
231 | | happens to use the notes obstack. */ |
232 | 0 | saved_string_obstack_end = obstack_next_free (¬es); |
233 | 0 | SKIP_WHITESPACE (); |
234 | 0 | if (*input_line_pointer == ',') |
235 | 0 | input_line_pointer++; |
236 | 0 | else |
237 | 0 | { |
238 | 0 | as_warn (_(".stab%c: missing comma"), what); |
239 | 0 | ignore_rest_of_line (); |
240 | 0 | return; |
241 | 0 | } |
242 | 0 | } |
243 | | |
244 | 808 | if (get_absolute_expression_and_terminator (&longint) != ',') |
245 | 5 | { |
246 | 5 | as_warn (_(".stab%c: missing comma"), what); |
247 | 5 | ignore_rest_of_line (); |
248 | 5 | return; |
249 | 5 | } |
250 | 803 | type = longint; |
251 | | |
252 | 803 | if (get_absolute_expression_and_terminator (&longint) != ',') |
253 | 86 | { |
254 | 86 | as_warn (_(".stab%c: missing comma"), what); |
255 | 86 | ignore_rest_of_line (); |
256 | 86 | return; |
257 | 86 | } |
258 | 717 | other = longint; |
259 | | |
260 | 717 | desc = get_absolute_expression (); |
261 | | |
262 | 717 | if ((desc > 0xffff) || (desc < -0x8000)) |
263 | | /* This could happen for example with a source file with a huge |
264 | | number of lines. The only cure is to use a different debug |
265 | | format, probably DWARF. */ |
266 | 1 | as_warn (_(".stab%c: description field '%x' too big, try a different debug format"), |
267 | 1 | what, desc); |
268 | | |
269 | 717 | if (what == 's' || what == 'n') |
270 | 717 | { |
271 | 717 | if (*input_line_pointer != ',') |
272 | 455 | { |
273 | 455 | as_warn (_(".stab%c: missing comma"), what); |
274 | 455 | ignore_rest_of_line (); |
275 | 455 | return; |
276 | 455 | } |
277 | 262 | input_line_pointer++; |
278 | 262 | SKIP_WHITESPACE (); |
279 | 262 | } |
280 | | |
281 | | #ifdef TC_PPC |
282 | | #ifdef OBJ_ELF |
283 | | /* Solaris on PowerPC has decided that .stabd can take 4 arguments, so if we were |
284 | | given 4 arguments, make it a .stabn */ |
285 | | else if (what == 'd') |
286 | | { |
287 | | char *save_location = input_line_pointer; |
288 | | |
289 | | SKIP_WHITESPACE (); |
290 | | if (*input_line_pointer == ',') |
291 | | { |
292 | | input_line_pointer++; |
293 | | what = 'n'; |
294 | | } |
295 | | else |
296 | | input_line_pointer = save_location; |
297 | | } |
298 | | #endif /* OBJ_ELF */ |
299 | | #endif /* TC_PPC */ |
300 | | |
301 | 262 | #ifndef NO_LISTING |
302 | 262 | if (listing) |
303 | 0 | { |
304 | 0 | switch (type) |
305 | 0 | { |
306 | 0 | case N_SLINE: |
307 | 0 | listing_source_line ((unsigned int) desc); |
308 | 0 | break; |
309 | 0 | case N_SO: |
310 | 0 | case N_SOL: |
311 | 0 | listing_source_file (string); |
312 | 0 | break; |
313 | 0 | } |
314 | 0 | } |
315 | 262 | #endif /* ! NO_LISTING */ |
316 | | |
317 | | /* We have now gathered the type, other, and desc information. For |
318 | | .stabs or .stabn, input_line_pointer is now pointing at the |
319 | | value. */ |
320 | | |
321 | 262 | if (SEPARATE_STAB_SECTIONS) |
322 | | /* Output the stab information in a separate section. This is used |
323 | | at least for COFF and ELF. */ |
324 | 262 | { |
325 | 262 | segT saved_seg = now_seg; |
326 | 262 | subsegT saved_subseg = now_subseg; |
327 | 262 | fragS *saved_frag = frag_now; |
328 | 262 | valueT dot; |
329 | 262 | segT seg; |
330 | 262 | unsigned int stroff; |
331 | 262 | char *p; |
332 | | |
333 | 262 | dot = frag_now_fix (); |
334 | | |
335 | | #ifdef md_flush_pending_output |
336 | | md_flush_pending_output (); |
337 | | #endif |
338 | | |
339 | 262 | if (cached_sec && strcmp (cached_sec->name, stab_secname) == 0) |
340 | 201 | { |
341 | 201 | seg = cached_sec; |
342 | 201 | subseg_set (seg, 0); |
343 | 201 | } |
344 | 61 | else |
345 | 61 | { |
346 | 61 | seg = subseg_new (stab_secname, 0); |
347 | 61 | cached_sec = seg; |
348 | 61 | } |
349 | | |
350 | 262 | if (! seg_info (seg)->hadone) |
351 | 61 | { |
352 | 61 | bfd_set_section_flags (seg, |
353 | 61 | SEC_READONLY | SEC_RELOC | SEC_DEBUGGING); |
354 | 61 | #ifdef INIT_STAB_SECTION |
355 | 61 | INIT_STAB_SECTION (seg); |
356 | 61 | #endif |
357 | 61 | seg_info (seg)->hadone = 1; |
358 | 61 | } |
359 | | |
360 | 262 | stroff = get_stab_string_offset (string, stabstr_secname, |
361 | 262 | stab_secname_obstack_end != NULL); |
362 | | |
363 | | /* Release the string, if nobody else has used the obstack. */ |
364 | 262 | if (saved_string_obstack_end != NULL |
365 | 262 | && saved_string_obstack_end == obstack_next_free (¬es)) |
366 | 0 | obstack_free (¬es, string); |
367 | | /* Similarly for the section name. This must be done before |
368 | | creating symbols below, which uses the notes obstack. */ |
369 | 262 | if (seg->name != stab_secname |
370 | 262 | && stab_secname_obstack_end != NULL |
371 | 262 | && stab_secname_obstack_end == obstack_next_free (¬es)) |
372 | 0 | obstack_free (¬es, stab_secname); |
373 | | |
374 | | /* At least for now, stabs in a special stab section are always |
375 | | output as 12 byte blocks of information. */ |
376 | 262 | p = frag_more (8); |
377 | 262 | md_number_to_chars (p, (valueT) stroff, 4); |
378 | 262 | md_number_to_chars (p + 4, (valueT) type, 1); |
379 | 262 | md_number_to_chars (p + 5, (valueT) other, 1); |
380 | 262 | md_number_to_chars (p + 6, (valueT) desc, 2); |
381 | | |
382 | 262 | if (what == 's' || what == 'n') |
383 | 262 | { |
384 | | /* Pick up the value from the input line. */ |
385 | 262 | cons (4); |
386 | 262 | input_line_pointer--; |
387 | 262 | } |
388 | 0 | else |
389 | 0 | { |
390 | 0 | symbolS *symbol; |
391 | 0 | expressionS exp; |
392 | | |
393 | | /* Arrange for a value representing the current location. */ |
394 | 0 | symbol = symbol_temp_new (saved_seg, saved_frag, dot); |
395 | |
|
396 | 0 | exp.X_op = O_symbol; |
397 | 0 | exp.X_add_symbol = symbol; |
398 | 0 | exp.X_add_number = 0; |
399 | |
|
400 | 0 | emit_expr (&exp, 4); |
401 | 0 | } |
402 | | |
403 | | #ifdef OBJ_PROCESS_STAB |
404 | | OBJ_PROCESS_STAB (seg, what, string, type, other, desc); |
405 | | #endif |
406 | | |
407 | 262 | subseg_set (saved_seg, saved_subseg); |
408 | 262 | } |
409 | 0 | else |
410 | 0 | { |
411 | 0 | if (stab_secname_obstack_end != NULL) |
412 | 0 | { |
413 | 0 | free ((char *) stabstr_secname); |
414 | 0 | if (stab_secname_obstack_end == obstack_next_free (¬es)) |
415 | 0 | obstack_free (¬es, stab_secname); |
416 | 0 | } |
417 | | #ifdef OBJ_PROCESS_STAB |
418 | | OBJ_PROCESS_STAB (0, what, string, type, other, desc); |
419 | | #else |
420 | 0 | abort (); |
421 | 0 | #endif |
422 | 0 | } |
423 | | |
424 | 262 | demand_empty_rest_of_line (); |
425 | 262 | } |
426 | | |
427 | | /* Regular stab directive. */ |
428 | | |
429 | | void |
430 | | s_stab (int what) |
431 | 837 | { |
432 | 837 | s_stab_generic (what, STAB_SECTION_NAME, STAB_STRING_SECTION_NAME, NULL); |
433 | 837 | } |
434 | | |
435 | | /* "Extended stabs", used in Solaris only now. */ |
436 | | |
437 | | void |
438 | | s_xstab (int what) |
439 | 0 | { |
440 | 0 | int length; |
441 | 0 | char *stab_secname, *stabstr_secname, *stab_secname_obstack_end; |
442 | |
|
443 | 0 | stab_secname = demand_copy_C_string (&length); |
444 | 0 | stab_secname_obstack_end = obstack_next_free (¬es); |
445 | 0 | SKIP_WHITESPACE (); |
446 | 0 | if (*input_line_pointer == ',') |
447 | 0 | input_line_pointer++; |
448 | 0 | else |
449 | 0 | { |
450 | 0 | as_bad (_("comma missing in .xstabs")); |
451 | 0 | ignore_rest_of_line (); |
452 | 0 | return; |
453 | 0 | } |
454 | | |
455 | | /* To get the name of the stab string section, simply add "str" to |
456 | | the stab section name. */ |
457 | 0 | stabstr_secname = concat (stab_secname, "str", (char *) NULL); |
458 | 0 | s_stab_generic (what, stab_secname, stabstr_secname, |
459 | 0 | stab_secname_obstack_end); |
460 | 0 | } |
461 | | |
462 | | #ifdef S_SET_DESC |
463 | | |
464 | | /* Frob invented at RMS' request. Set the n_desc of a symbol. */ |
465 | | |
466 | | void |
467 | | s_desc (int ignore ATTRIBUTE_UNUSED) |
468 | | { |
469 | | char *name; |
470 | | char c; |
471 | | char *p; |
472 | | symbolS *symbolP; |
473 | | int temp; |
474 | | |
475 | | c = get_symbol_name (&name); |
476 | | p = input_line_pointer; |
477 | | *p = c; |
478 | | SKIP_WHITESPACE_AFTER_NAME (); |
479 | | if (*input_line_pointer != ',') |
480 | | { |
481 | | *p = 0; |
482 | | as_bad (_("expected comma after \"%s\""), name); |
483 | | *p = c; |
484 | | ignore_rest_of_line (); |
485 | | } |
486 | | else |
487 | | { |
488 | | input_line_pointer++; |
489 | | temp = get_absolute_expression (); |
490 | | *p = 0; |
491 | | symbolP = symbol_find_or_make (name); |
492 | | *p = c; |
493 | | S_SET_DESC (symbolP, temp); |
494 | | } |
495 | | demand_empty_rest_of_line (); |
496 | | } /* s_desc() */ |
497 | | |
498 | | #endif /* defined (S_SET_DESC) */ |
499 | | |
500 | | /* Generate stabs debugging information to denote the main source file. */ |
501 | | |
502 | | void |
503 | | stabs_generate_asm_file (void) |
504 | 0 | { |
505 | 0 | const char *file; |
506 | 0 | unsigned int lineno; |
507 | |
|
508 | 0 | file = as_where (&lineno); |
509 | 0 | if (use_gnu_debug_info_extensions) |
510 | 0 | { |
511 | 0 | char *dir; |
512 | 0 | char *dir2; |
513 | |
|
514 | 0 | dir = remap_debug_filename (getpwd ()); |
515 | 0 | dir2 = concat (dir, "/", NULL); |
516 | 0 | generate_asm_file (N_SO, dir2); |
517 | 0 | free (dir2); |
518 | 0 | free (dir); |
519 | 0 | } |
520 | 0 | generate_asm_file (N_SO, file); |
521 | 0 | } |
522 | | |
523 | | /* Generate stabs debugging information to denote the source file. |
524 | | TYPE is one of N_SO, N_SOL. */ |
525 | | |
526 | | static void |
527 | | generate_asm_file (int type, const char *file) |
528 | 0 | { |
529 | 0 | char sym[30]; |
530 | 0 | char *buf; |
531 | 0 | const char *tmp = file; |
532 | 0 | const char *file_endp = file + strlen (file); |
533 | 0 | char *bufp; |
534 | |
|
535 | 0 | if (last_asm_file != NULL |
536 | 0 | && filename_cmp (last_asm_file, file) == 0) |
537 | 0 | return; |
538 | | |
539 | | /* Rather than try to do this in some efficient fashion, we just |
540 | | generate a string and then parse it again. That lets us use the |
541 | | existing stabs hook, which expect to see a string, rather than |
542 | | inventing new ones. */ |
543 | 0 | sprintf (sym, "%sF%d", FAKE_LABEL_NAME, file_label_count); |
544 | 0 | ++file_label_count; |
545 | | |
546 | | /* Allocate enough space for the file name (possibly extended with |
547 | | doubled up backslashes), the symbol name, and the other characters |
548 | | that make up a stabs file directive. */ |
549 | 0 | bufp = buf = XNEWVEC (char, 2 * strlen (file) + strlen (sym) + 12); |
550 | |
|
551 | 0 | *bufp++ = '"'; |
552 | |
|
553 | 0 | while (tmp < file_endp) |
554 | 0 | { |
555 | 0 | const char *bslash = strchr (tmp, '\\'); |
556 | 0 | size_t len = bslash != NULL ? bslash - tmp + 1 : file_endp - tmp; |
557 | | |
558 | | /* Double all backslashes, since demand_copy_C_string (used by |
559 | | s_stab to extract the part in quotes) will try to replace them as |
560 | | escape sequences. backslash may appear in a filespec. */ |
561 | 0 | memcpy (bufp, tmp, len); |
562 | |
|
563 | 0 | tmp += len; |
564 | 0 | bufp += len; |
565 | |
|
566 | 0 | if (bslash != NULL) |
567 | 0 | *bufp++ = '\\'; |
568 | 0 | } |
569 | |
|
570 | 0 | sprintf (bufp, "\",%d,0,0,%s\n", type, sym); |
571 | |
|
572 | 0 | temp_ilp (buf); |
573 | 0 | s_stab ('s'); |
574 | 0 | restore_ilp (); |
575 | |
|
576 | 0 | colon (sym); |
577 | |
|
578 | 0 | free (last_asm_file); |
579 | 0 | last_asm_file = xstrdup (file); |
580 | |
|
581 | 0 | free (buf); |
582 | 0 | } |
583 | | |
584 | | /* Generate stabs debugging information for the current line. This is |
585 | | used to produce debugging information for an assembler file. */ |
586 | | |
587 | | void |
588 | | stabs_generate_asm_lineno (void) |
589 | 0 | { |
590 | 0 | const char *file; |
591 | 0 | unsigned int lineno; |
592 | 0 | char *buf; |
593 | 0 | char sym[30]; |
594 | | |
595 | | /* Rather than try to do this in some efficient fashion, we just |
596 | | generate a string and then parse it again. That lets us use the |
597 | | existing stabs hook, which expect to see a string, rather than |
598 | | inventing new ones. */ |
599 | |
|
600 | 0 | file = as_where (&lineno); |
601 | | |
602 | | /* Don't emit sequences of stabs for the same line. */ |
603 | 0 | if (prev_line_file != NULL |
604 | 0 | && filename_cmp (file, prev_line_file) == 0) |
605 | 0 | { |
606 | 0 | if (lineno == prev_lineno) |
607 | | /* Same file/line as last time. */ |
608 | 0 | return; |
609 | 0 | } |
610 | 0 | else |
611 | 0 | { |
612 | | /* Remember file/line for next time. */ |
613 | 0 | free (prev_line_file); |
614 | 0 | prev_line_file = xstrdup (file); |
615 | 0 | } |
616 | | |
617 | 0 | prev_lineno = lineno; |
618 | | |
619 | | /* Let the world know that we are in the middle of generating a |
620 | | piece of stabs line debugging information. */ |
621 | 0 | outputting_stabs_line_debug = 1; |
622 | |
|
623 | 0 | generate_asm_file (N_SOL, file); |
624 | |
|
625 | 0 | sprintf (sym, "%sL%d", FAKE_LABEL_NAME, line_label_count); |
626 | 0 | ++line_label_count; |
627 | |
|
628 | 0 | if (current_function_label) |
629 | 0 | { |
630 | 0 | buf = XNEWVEC (char, 100 + strlen (current_function_label)); |
631 | 0 | sprintf (buf, "%d,0,%d,%s-%s\n", N_SLINE, lineno, |
632 | 0 | sym, current_function_label); |
633 | 0 | } |
634 | 0 | else |
635 | 0 | { |
636 | 0 | buf = XNEWVEC (char, 100); |
637 | 0 | sprintf (buf, "%d,0,%d,%s\n", N_SLINE, lineno, sym); |
638 | 0 | } |
639 | |
|
640 | 0 | temp_ilp (buf); |
641 | 0 | s_stab ('n'); |
642 | 0 | restore_ilp (); |
643 | |
|
644 | 0 | colon (sym); |
645 | |
|
646 | 0 | outputting_stabs_line_debug = 0; |
647 | 0 | free (buf); |
648 | 0 | } |
649 | | |
650 | | /* Emit a function stab. |
651 | | All assembler functions are assumed to have return type `void'. */ |
652 | | |
653 | | void |
654 | | stabs_generate_asm_func (const char *funcname, const char *startlabname) |
655 | 0 | { |
656 | 0 | char *buf; |
657 | 0 | unsigned int lineno; |
658 | |
|
659 | 0 | if (! void_emitted_p) |
660 | 0 | { |
661 | 0 | temp_ilp ((char *) "\"void:t1=1\",128,0,0,0"); |
662 | 0 | s_stab ('s'); |
663 | 0 | restore_ilp (); |
664 | 0 | void_emitted_p = true; |
665 | 0 | } |
666 | |
|
667 | 0 | as_where (&lineno); |
668 | 0 | if (asprintf (&buf, "\"%s:F1\",%d,0,%d,%s", |
669 | 0 | funcname, N_FUN, lineno + 1, startlabname) == -1) |
670 | 0 | as_fatal ("%s", xstrerror (errno)); |
671 | | |
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 = xstrdup (startlabname); |
679 | 0 | } |
680 | | |
681 | | /* Emit a stab to record the end of a function. */ |
682 | | |
683 | | void |
684 | | stabs_generate_asm_endfunc (const char *funcname ATTRIBUTE_UNUSED, |
685 | | const char *startlabname) |
686 | 0 | { |
687 | 0 | char *buf; |
688 | 0 | char sym[30]; |
689 | |
|
690 | 0 | sprintf (sym, "%sendfunc%d", FAKE_LABEL_NAME, endfunc_label_count); |
691 | 0 | ++endfunc_label_count; |
692 | 0 | colon (sym); |
693 | |
|
694 | 0 | if (asprintf (&buf, "\"\",%d,0,0,%s-%s", N_FUN, sym, startlabname) == -1) |
695 | 0 | as_fatal ("%s", xstrerror (errno)); |
696 | | |
697 | 0 | temp_ilp (buf); |
698 | 0 | s_stab ('s'); |
699 | 0 | restore_ilp (); |
700 | 0 | free (buf); |
701 | |
|
702 | 0 | free ((char *) current_function_label); |
703 | 0 | current_function_label = NULL; |
704 | 0 | } |
705 | | |
706 | | void |
707 | | stabs_begin (void) |
708 | 1.15k | { |
709 | 1.15k | current_function_label = NULL; |
710 | 1.15k | cached_sec = NULL; |
711 | 1.15k | last_asm_file = NULL; |
712 | 1.15k | file_label_count = 0; |
713 | 1.15k | line_label_count = 0; |
714 | 1.15k | prev_lineno = -1u; |
715 | 1.15k | prev_line_file = NULL; |
716 | 1.15k | void_emitted_p = false; |
717 | 1.15k | endfunc_label_count = 0; |
718 | 1.15k | } |
719 | | |
720 | | void |
721 | | stabs_end (void) |
722 | 1.15k | { |
723 | 1.15k | free ((char *) current_function_label); |
724 | 1.15k | free (last_asm_file); |
725 | 1.15k | free (prev_line_file); |
726 | 1.15k | } |