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