Commit | Line | Data |
---|---|---|
3f43243e WJ |
1 | /* Output dbx-format symbol table information from GNU compiler. |
2 | Copyright (C) 1987, 1988 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of GNU CC. | |
5 | ||
6 | GNU CC is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 1, or (at your option) | |
9 | any later version. | |
10 | ||
11 | GNU CC is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GNU CC; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
19 | ||
20 | ||
21 | /* Output dbx-format symbol table data. | |
22 | This consists of many symbol table entries, each of them | |
23 | a .stabs assembler pseudo-op with four operands: | |
24 | a "name" which is really a description of one symbol and its type, | |
25 | a "code", which is a symbol defined in stab.h whose name starts with N_, | |
26 | an unused operand always 0, | |
27 | and a "value" which is an address or an offset. | |
28 | The name is enclosed in doublequote characters. | |
29 | ||
30 | Each function, variable, typedef, and structure tag | |
31 | has a symbol table entry to define it. | |
32 | The beginning and end of each level of name scoping within | |
33 | a function are also marked by special symbol table entries. | |
34 | ||
35 | The "name" consists of the symbol name, a colon, a kind-of-symbol letter, | |
36 | and a data type number. The data type number may be followed by | |
37 | "=" and a type definition; normally this will happen the first time | |
38 | the type number is mentioned. The type definition may refer to | |
39 | other types by number, and those type numbers may be followed | |
40 | by "=" and nested definitions. | |
41 | ||
42 | This can make the "name" quite long. | |
43 | When a name is more than 80 characters, we split the .stabs pseudo-op | |
44 | into two .stabs pseudo-ops, both sharing the same "code" and "value". | |
45 | The first one is marked as continued with a double-backslash at the | |
46 | end of its "name". | |
47 | ||
48 | The kind-of-symbol letter distinguished function names from global | |
49 | variables from file-scope variables from parameters from auto | |
50 | variables in memory from typedef names from register variables. | |
51 | See `dbxout_symbol'. | |
52 | ||
53 | The "code" is mostly redundant with the kind-of-symbol letter | |
54 | that goes in the "name", but not entirely: for symbols located | |
55 | in static storage, the "code" says which segment the address is in, | |
56 | which controls how it is relocated. | |
57 | ||
58 | The "value" for a symbol in static storage | |
59 | is the core address of the symbol (actually, the assembler | |
60 | label for the symbol). For a symbol located in a stack slot | |
61 | it is the stack offset; for one in a register, the register number. | |
62 | For a typedef symbol, it is zero. | |
63 | ||
64 | If DEBUG_SYMS_TEXT is defined, all debugging symbols must be | |
65 | output while in the text section. | |
66 | ||
67 | For more on data type definitions, see `dbxout_type'. */ | |
68 | ||
69 | #include "config.h" | |
70 | #include "tree.h" | |
71 | #include "rtl.h" | |
72 | #include "flags.h" | |
73 | #include <stdio.h> | |
74 | ||
75 | /* Typical USG systems don't have stab.h, and they also have | |
76 | no use for DBX-format debugging info. */ | |
77 | ||
78 | #ifdef DBX_DEBUGGING_INFO | |
79 | ||
80 | #ifdef DEBUG_SYMS_TEXT | |
81 | #define FORCE_TEXT text_section (); | |
82 | #else | |
83 | #define FORCE_TEXT | |
84 | #endif | |
85 | ||
86 | #ifdef USG | |
87 | #include "stab.h" /* If doing DBX on sysV, use our own stab.h. */ | |
88 | #else | |
89 | #include <stab.h> /* On BSD, use the system's stab.h. */ | |
90 | #endif /* not USG */ | |
91 | ||
92 | /* Stream for writing to assembler file. */ | |
93 | ||
94 | static FILE *asmfile; | |
95 | ||
96 | enum typestatus {TYPE_UNSEEN, TYPE_XREF, TYPE_DEFINED}; | |
97 | ||
98 | /* Vector recording the status of describing C data types. | |
99 | When we first notice a data type (a tree node), | |
100 | we assign it a number using next_type_number. | |
101 | That is its index in this vector. | |
102 | The vector element says whether we have yet output | |
103 | the definition of the type. TYPE_XREF says we have | |
104 | output it as a cross-reference only. */ | |
105 | ||
106 | enum typestatus *typevec; | |
107 | ||
108 | /* Number of elements of space allocated in `typevec'. */ | |
109 | ||
110 | static int typevec_len; | |
111 | ||
112 | /* In dbx output, each type gets a unique number. | |
113 | This is the number for the next type output. | |
114 | The number, once assigned, is in the TYPE_SYMTAB_ADDRESS field. */ | |
115 | ||
116 | static int next_type_number; | |
117 | ||
118 | /* In dbx output, we must assign symbol-blocks id numbers | |
119 | in the order in which their beginnings are encountered. | |
120 | We output debugging info that refers to the beginning and | |
121 | end of the ranges of code in each block | |
122 | with assembler labels LBBn and LBEn, where n is the block number. | |
123 | The labels are generated in final, which assigns numbers to the | |
124 | blocks in the same way. */ | |
125 | ||
126 | static int next_block_number; | |
127 | ||
128 | /* These variables are for dbxout_symbol to communicate to | |
129 | dbxout_finish_symbol. | |
130 | current_sym_code is the symbol-type-code, a symbol N_... define in stab.h. | |
131 | current_sym_value and current_sym_addr are two ways to address the | |
132 | value to store in the symtab entry. | |
133 | current_sym_addr if nonzero represents the value as an rtx. | |
134 | If that is zero, current_sym_value is used. This is used | |
135 | when the value is an offset (such as for auto variables, | |
136 | register variables and parms). */ | |
137 | ||
138 | static int current_sym_code; | |
139 | static int current_sym_value; | |
140 | static rtx current_sym_addr; | |
141 | ||
142 | /* Number of chars of symbol-description generated so far for the | |
143 | current symbol. Used by CHARS and CONTIN. */ | |
144 | ||
145 | static int current_sym_nchars; | |
146 | ||
147 | /* Report having output N chars of the current symbol-description. */ | |
148 | ||
149 | #define CHARS(N) (current_sym_nchars += (N)) | |
150 | ||
151 | /* Break the current symbol-description, generating a continuation, | |
152 | if it has become long. */ | |
153 | ||
154 | #ifndef DBX_CONTIN_LENGTH | |
155 | #define DBX_CONTIN_LENGTH 80 | |
156 | #endif | |
157 | ||
158 | #if DBX_CONTIN_LENGTH > 0 | |
159 | #define CONTIN \ | |
160 | do {if (current_sym_nchars > DBX_CONTIN_LENGTH) dbxout_continue ();} while (0) | |
161 | #else | |
162 | #define CONTIN | |
163 | #endif | |
164 | ||
165 | void dbxout_types (); | |
166 | void dbxout_tags (); | |
167 | void dbxout_args (); | |
168 | void dbxout_symbol (); | |
169 | static void dbxout_type_name (); | |
170 | static void dbxout_type (); | |
171 | static void dbxout_finish_symbol (); | |
172 | static void dbxout_continue (); | |
173 | \f | |
174 | /* At the beginning of compilation, start writing the symbol table. | |
175 | Initialize `typevec' and output the standard data types of C. */ | |
176 | ||
177 | void | |
178 | dbxout_init (asm_file, input_file_name) | |
179 | FILE *asm_file; | |
180 | char *input_file_name; | |
181 | { | |
182 | asmfile = asm_file; | |
183 | ||
184 | typevec_len = 100; | |
185 | typevec = (enum typestatus *) xmalloc (typevec_len * sizeof typevec[0]); | |
186 | bzero (typevec, typevec_len * sizeof typevec[0]); | |
187 | ||
188 | /* Used to put `Ltext:' before the reference, but that loses on sun 4. */ | |
189 | fprintf (asmfile, | |
190 | "\t.stabs \"%s\",%d,0,0,Ltext\nLtext:\n", | |
191 | input_file_name, N_SO); | |
192 | ||
193 | next_type_number = 1; | |
194 | next_block_number = 2; | |
195 | ||
196 | /* Make sure that types `int' and `char' have numbers 1 and 2. | |
197 | Definitions of other integer types will refer to those numbers. */ | |
198 | ||
199 | dbxout_symbol (TYPE_NAME (integer_type_node), 0); | |
200 | dbxout_symbol (TYPE_NAME (char_type_node), 0); | |
201 | ||
202 | /* Get all permanent types not yet gotten, and output them. */ | |
203 | ||
204 | dbxout_types (get_permanent_types ()); | |
205 | } | |
206 | ||
207 | /* Continue a symbol-description that gets too big. | |
208 | End one symbol table entry with a double-backslash | |
209 | and start a new one, eventually producing something like | |
210 | .stabs "start......\\",code,0,value | |
211 | .stabs "...rest",code,0,value */ | |
212 | ||
213 | static void | |
214 | dbxout_continue () | |
215 | { | |
216 | #ifdef DBX_CONTIN_CHAR | |
217 | fprintf (asmfile, "%c", DBX_CONTIN_CHAR); | |
218 | #else | |
219 | fprintf (asmfile, "\\\\"); | |
220 | #endif | |
221 | dbxout_finish_symbol (); | |
222 | fprintf (asmfile, ".stabs \""); | |
223 | current_sym_nchars = 0; | |
224 | } | |
225 | \f | |
226 | /* Output a reference to a type. If the type has not yet been | |
227 | described in the dbx output, output its definition now. | |
228 | For a type already defined, just refer to its definition | |
229 | using the type number. | |
230 | ||
231 | If FULL is nonzero, and the type has been described only with | |
232 | a forward-reference, output the definition now. | |
233 | If FULL is zero in this case, just refer to the forward-reference | |
234 | using the number previously allocated. */ | |
235 | ||
236 | static void | |
237 | dbxout_type (type, full) | |
238 | tree type; | |
239 | int full; | |
240 | { | |
241 | register tree tem; | |
242 | ||
243 | /* If there was an input error and we don't really have a type, | |
244 | avoid crashing and write something that is at least valid | |
245 | by assuming `int'. */ | |
246 | if (type == error_mark_node) | |
247 | type = integer_type_node; | |
248 | else | |
249 | type = TYPE_MAIN_VARIANT (type); | |
250 | ||
251 | if (TYPE_SYMTAB_ADDRESS (type) == 0) | |
252 | { | |
253 | /* Type has no dbx number assigned. Assign next available number. */ | |
254 | TYPE_SYMTAB_ADDRESS (type) = next_type_number++; | |
255 | ||
256 | /* Make sure type vector is long enough to record about this type. */ | |
257 | ||
258 | if (next_type_number == typevec_len) | |
259 | { | |
260 | typevec = (enum typestatus *) xrealloc (typevec, typevec_len * 2 * sizeof typevec[0]); | |
261 | bzero (typevec + typevec_len, typevec_len * sizeof typevec[0]); | |
262 | typevec_len *= 2; | |
263 | } | |
264 | } | |
265 | ||
266 | /* Output the number of this type, to refer to it. */ | |
267 | fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type)); | |
268 | CHARS (3); | |
269 | ||
270 | /* If this type's definition has been output or is now being output, | |
271 | that is all. */ | |
272 | ||
273 | switch (typevec[TYPE_SYMTAB_ADDRESS (type)]) | |
274 | { | |
275 | case TYPE_UNSEEN: | |
276 | break; | |
277 | case TYPE_XREF: | |
278 | if (! full) | |
279 | return; | |
280 | break; | |
281 | case TYPE_DEFINED: | |
282 | return; | |
283 | } | |
284 | ||
285 | #ifdef DBX_NO_XREFS | |
286 | /* For systems where dbx output does not allow the `=xsNAME:' syntax, | |
287 | leave the type-number completely undefined rather than output | |
288 | a cross-reference. */ | |
289 | if (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE | |
290 | || TREE_CODE (type) == ENUMERAL_TYPE) | |
291 | ||
292 | if ((TYPE_NAME (type) != 0 && !full) | |
293 | || TYPE_SIZE (type) == 0) | |
294 | { | |
295 | typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF; | |
296 | return; | |
297 | } | |
298 | #endif | |
299 | ||
300 | /* Output a definition now. */ | |
301 | ||
302 | fprintf (asmfile, "="); | |
303 | CHARS (1); | |
304 | ||
305 | /* Mark it as defined, so that if it is self-referent | |
306 | we will not get into an infinite recursion of definitions. */ | |
307 | ||
308 | typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_DEFINED; | |
309 | ||
310 | switch (TREE_CODE (type)) | |
311 | { | |
312 | case VOID_TYPE: | |
313 | /* For a void type, just define it as itself; ie, "5=5". | |
314 | This makes us consider it defined | |
315 | without saying what it is. The debugger will make it | |
316 | a void type when the reference is seen, and nothing will | |
317 | ever override that default. */ | |
318 | fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type)); | |
319 | CHARS (3); | |
320 | break; | |
321 | ||
322 | case INTEGER_TYPE: | |
323 | if (type == char_type_node && ! TREE_UNSIGNED (type)) | |
324 | /* Output the type `char' as a subrange of itself! | |
325 | I don't understand this definition, just copied it | |
326 | from the output of pcc. */ | |
327 | fprintf (asmfile, "r2;0;127;"); | |
328 | else | |
329 | /* Output other integer types as subranges of `int'. */ | |
330 | fprintf (asmfile, "r1;%d;%d;", | |
331 | TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)), | |
332 | TREE_INT_CST_LOW (TYPE_MAX_VALUE (type))); | |
333 | CHARS (25); | |
334 | break; | |
335 | ||
336 | case REAL_TYPE: | |
337 | /* This must be magic. */ | |
338 | fprintf (asmfile, "r1;%d;0;", | |
339 | TREE_INT_CST_LOW (size_in_bytes (type))); | |
340 | CHARS (16); | |
341 | break; | |
342 | ||
343 | case ARRAY_TYPE: | |
344 | /* Output "a" followed by a range type definition | |
345 | for the index type of the array | |
346 | followed by a reference to the target-type. | |
347 | ar1;0;N;M for an array of type M and size N. */ | |
348 | fprintf (asmfile, "ar1;0;%d;", | |
349 | (TYPE_DOMAIN (type) | |
350 | ? TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) | |
351 | : -1)); | |
352 | CHARS (17); | |
353 | dbxout_type (TREE_TYPE (type), 0); | |
354 | break; | |
355 | ||
356 | case RECORD_TYPE: | |
357 | case UNION_TYPE: | |
358 | /* Output a structure type. */ | |
359 | if ((TYPE_NAME (type) != 0 && !full) | |
360 | || TYPE_SIZE (type) == 0) | |
361 | { | |
362 | /* If the type is just a cross reference, output one | |
363 | and mark the type as partially described. | |
364 | If it later becomes defined, we will output | |
365 | its real definition. | |
366 | If the type has a name, don't nest its definition within | |
367 | another type's definition; instead, output an xref | |
368 | and let the definition come when the name is defined. */ | |
369 | fprintf (asmfile, (TREE_CODE (type) == RECORD_TYPE) ? "xs" : "xu"); | |
370 | CHARS (3); | |
371 | #if 0 /* This assertion is legitimately false in C++. */ | |
372 | /* We shouldn't be outputting a reference to a type before its | |
373 | definition unless the type has a tag name. | |
374 | A typedef name without a tag name should be impossible. */ | |
375 | if (TREE_CODE (TYPE_NAME (type)) != IDENTIFIER_NODE) | |
376 | abort (); | |
377 | #endif | |
378 | dbxout_type_name (type); | |
379 | fprintf (asmfile, ":"); | |
380 | typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF; | |
381 | break; | |
382 | } | |
383 | tem = size_in_bytes (type); | |
384 | fprintf (asmfile, (TREE_CODE (type) == RECORD_TYPE) ? "s%d" : "u%d", | |
385 | TREE_INT_CST_LOW (tem)); | |
386 | ||
387 | if (TYPE_BASETYPES (type) && use_gdb_dbx_extensions) | |
388 | { | |
389 | putc ('!', asmfile); | |
390 | putc ((TREE_PUBLIC (TYPE_BASETYPES (type)) ? '2' : '0'), | |
391 | asmfile); | |
392 | dbxout_type (TREE_VALUE (TYPE_BASETYPES (type)), 0); | |
393 | putc (',', asmfile); | |
394 | CHARS (3); | |
395 | } | |
396 | CHARS (11); | |
397 | ||
398 | for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) | |
399 | /* Output the name, type, position (in bits), size (in bits) | |
400 | of each field. */ | |
401 | /* Omit here the nameless fields that are used to skip bits. */ | |
402 | if (DECL_NAME (tem) != 0) | |
403 | { | |
404 | /* Continue the line if necessary, | |
405 | but not before the first field. */ | |
406 | if (tem != TYPE_FIELDS (type)) | |
407 | CONTIN; | |
408 | fprintf (asmfile, "%s:", IDENTIFIER_POINTER (DECL_NAME (tem))); | |
409 | CHARS (2 + IDENTIFIER_LENGTH (DECL_NAME (tem))); | |
410 | #ifdef TREE_PRIVATE | |
411 | if (use_gdb_dbx_extensions | |
412 | && (TREE_PRIVATE (tem) || TREE_PROTECTED (tem) | |
413 | || TREE_CODE (tem) != FIELD_DECL)) | |
414 | { | |
415 | putc ('/', asmfile); | |
416 | putc ((TREE_PRIVATE (tem) ? '0' | |
417 | : TREE_PROTECTED (tem) ? '1' : '2'), | |
418 | asmfile); | |
419 | CHARS (2); | |
420 | if (TREE_CODE (tem) == FUNCTION_DECL) | |
421 | { | |
422 | putc (':', asmfile); | |
423 | CHARS (1); | |
424 | dbxout_type (TREE_TYPE (tem), 0); /* FUNCTION_TYPE */ | |
425 | dbxout_args (TYPE_ARG_TYPES (TREE_TYPE (tem))); | |
426 | #ifdef TREE_VIRTUAL | |
427 | fprintf (asmfile, ":%s;%c", | |
428 | XSTR (XEXP (DECL_RTL (tem), 0), 0), | |
429 | TREE_VIRTUAL (tem) ? '*' : '.'); | |
430 | #endif | |
431 | CHARS (3 + strlen (XSTR (XEXP (DECL_RTL (tem), 0), 0))); | |
432 | } | |
433 | else | |
434 | dbxout_type (TREE_TYPE (tem), 0); | |
435 | } | |
436 | else | |
437 | #endif | |
438 | dbxout_type (TREE_TYPE (tem), 0); | |
439 | ||
440 | if (TREE_CODE (tem) == VAR_DECL) | |
441 | { | |
442 | if (use_gdb_dbx_extensions) | |
443 | { | |
444 | fprintf (asmfile, ":%s", | |
445 | XSTR (XEXP (DECL_RTL (tem), 0), 0)); | |
446 | CHARS (2 + strlen (XSTR (XEXP (DECL_RTL (tem), 0), 0))); | |
447 | } | |
448 | else | |
449 | { | |
450 | fprintf (asmfile, ",0,0;"); | |
451 | CHARS (5); | |
452 | } | |
453 | } | |
454 | else | |
455 | { | |
456 | fprintf (asmfile, ",%d,%d;", DECL_OFFSET (tem), | |
457 | (TREE_INT_CST_LOW (DECL_SIZE (tem)) | |
458 | * DECL_SIZE_UNIT (tem))); | |
459 | CHARS (23); | |
460 | } | |
461 | } | |
462 | ||
463 | putc (';', asmfile); | |
464 | CHARS (1); | |
465 | break; | |
466 | ||
467 | case ENUMERAL_TYPE: | |
468 | if ((TYPE_NAME (type) != 0 && !full) | |
469 | || TYPE_SIZE (type) == 0) | |
470 | { | |
471 | fprintf (asmfile, "xe"); | |
472 | CHARS (3); | |
473 | dbxout_type_name (type); | |
474 | typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF; | |
475 | fprintf (asmfile, ":"); | |
476 | return; | |
477 | } | |
478 | putc ('e', asmfile); | |
479 | CHARS (1); | |
480 | for (tem = TYPE_VALUES (type); tem; tem = TREE_CHAIN (tem)) | |
481 | { | |
482 | fprintf (asmfile, "%s:%d,", IDENTIFIER_POINTER (TREE_PURPOSE (tem)), | |
483 | TREE_INT_CST_LOW (TREE_VALUE (tem))); | |
484 | CHARS (11 + IDENTIFIER_LENGTH (TREE_PURPOSE (tem))); | |
485 | if (TREE_CHAIN (tem) != 0) | |
486 | CONTIN; | |
487 | } | |
488 | putc (';', asmfile); | |
489 | CHARS (1); | |
490 | break; | |
491 | ||
492 | case POINTER_TYPE: | |
493 | putc ('*', asmfile); | |
494 | CHARS (1); | |
495 | dbxout_type (TREE_TYPE (type), 0); | |
496 | break; | |
497 | ||
498 | case METHOD_TYPE: | |
499 | if (use_gdb_dbx_extensions) | |
500 | { | |
501 | putc ('@', asmfile); | |
502 | CHARS (1); | |
503 | dbxout_type (TYPE_METHOD_BASETYPE (type), 0); | |
504 | putc (',', asmfile); | |
505 | CHARS (1); | |
506 | dbxout_type (TREE_TYPE (type), 0); | |
507 | } | |
508 | else | |
509 | { | |
510 | /* Treat it as a function type. */ | |
511 | dbxout_type (TREE_TYPE (type), 0); | |
512 | } | |
513 | break; | |
514 | ||
515 | case OFFSET_TYPE: | |
516 | if (use_gdb_dbx_extensions) | |
517 | { | |
518 | putc ('@', asmfile); | |
519 | CHARS (1); | |
520 | dbxout_type (TYPE_OFFSET_BASETYPE (type), 0); | |
521 | putc (',', asmfile); | |
522 | CHARS (1); | |
523 | dbxout_type (TREE_TYPE (type), 0); | |
524 | } | |
525 | else | |
526 | { | |
527 | /* Treat it as a function type. */ | |
528 | dbxout_type (TREE_TYPE (type), 0); | |
529 | } | |
530 | break; | |
531 | ||
532 | case REFERENCE_TYPE: | |
533 | putc (use_gdb_dbx_extensions ? '&' : '*', asmfile); | |
534 | CHARS (1); | |
535 | dbxout_type (TREE_TYPE (type), 0); | |
536 | break; | |
537 | ||
538 | case FUNCTION_TYPE: | |
539 | putc ('f', asmfile); | |
540 | CHARS (1); | |
541 | dbxout_type (TREE_TYPE (type), 0); | |
542 | break; | |
543 | ||
544 | default: | |
545 | abort (); | |
546 | } | |
547 | } | |
548 | ||
549 | /* Output the name of type TYPE, with no punctuation. | |
550 | Such names can be set up either by typedef declarations | |
551 | or by struct, enum and union tags. */ | |
552 | ||
553 | static void | |
554 | dbxout_type_name (type) | |
555 | register tree type; | |
556 | { | |
557 | tree t; | |
558 | if (TYPE_NAME (type) == 0) | |
559 | abort (); | |
560 | if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) | |
561 | { | |
562 | t = TYPE_NAME (type); | |
563 | } | |
564 | else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL) | |
565 | { | |
566 | t = DECL_NAME (TYPE_NAME (type)); | |
567 | } | |
568 | else | |
569 | abort (); | |
570 | ||
571 | fprintf (asmfile, "%s", IDENTIFIER_POINTER (t)); | |
572 | CHARS (IDENTIFIER_LENGTH (t)); | |
573 | } | |
574 | \f | |
575 | /* Output a .stabs for the symbol defined by DECL, | |
576 | which must be a ..._DECL node in the normal namespace. | |
577 | It may be a CONST_DECL, a FUNCTION_DECL, a PARM_DECL or a VAR_DECL. | |
578 | LOCAL is nonzero if the scope is less than the entire file. */ | |
579 | ||
580 | void | |
581 | dbxout_symbol (decl, local) | |
582 | tree decl; | |
583 | int local; | |
584 | { | |
585 | int letter = 0; | |
586 | tree type = TREE_TYPE (decl); | |
587 | ||
588 | /* If global, first output all types and all | |
589 | struct, enum and union tags that have been created | |
590 | and not yet output. */ | |
591 | ||
592 | if (local == 0) | |
593 | { | |
594 | dbxout_tags (gettags ()); | |
595 | dbxout_types (get_permanent_types ()); | |
596 | } | |
597 | ||
598 | current_sym_code = 0; | |
599 | current_sym_value = 0; | |
600 | current_sym_addr = 0; | |
601 | ||
602 | /* The output will always start with the symbol name, | |
603 | so count that always in the length-output-so-far. */ | |
604 | ||
605 | current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (decl)); | |
606 | ||
607 | switch (TREE_CODE (decl)) | |
608 | { | |
609 | case CONST_DECL: | |
610 | /* Enum values are defined by defining the enum type. */ | |
611 | break; | |
612 | ||
613 | case FUNCTION_DECL: | |
614 | if (DECL_RTL (decl) == 0) | |
615 | return; | |
616 | if (TREE_EXTERNAL (decl)) | |
617 | break; | |
618 | if (GET_CODE (DECL_RTL (decl)) != MEM | |
619 | || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF) | |
620 | break; | |
621 | FORCE_TEXT; | |
622 | fprintf (asmfile, ".stabs \"%s:%c", | |
623 | IDENTIFIER_POINTER (DECL_NAME (decl)), | |
624 | TREE_PUBLIC (decl) ? 'F' : 'f'); | |
625 | ||
626 | current_sym_code = N_FUN; | |
627 | current_sym_addr = XEXP (DECL_RTL (decl), 0); | |
628 | ||
629 | if (TREE_TYPE (TREE_TYPE (decl))) | |
630 | dbxout_type (TREE_TYPE (TREE_TYPE (decl)), 0); | |
631 | else | |
632 | dbxout_type (void_type_node, 0); | |
633 | dbxout_finish_symbol (); | |
634 | break; | |
635 | ||
636 | case TYPE_DECL: | |
637 | #if 0 | |
638 | /* This seems all wrong. Outputting most kinds of types gives no name | |
639 | at all. A true definition gives no name; a cross-ref for a | |
640 | structure can give the tag name, but not a type name. | |
641 | It seems that no typedef name is defined by outputting a type. */ | |
642 | ||
643 | /* If this typedef name was defined by outputting the type, | |
644 | don't duplicate it. */ | |
645 | if (typevec[TYPE_SYMTAB_ADDRESS (type)] == TYPE_DEFINED | |
646 | && TYPE_NAME (TREE_TYPE (decl)) == decl) | |
647 | return; | |
648 | #endif | |
649 | /* Don't output the same typedef twice. */ | |
650 | if (TREE_ASM_WRITTEN (decl)) | |
651 | return; | |
652 | ||
653 | /* Output typedef name. */ | |
654 | FORCE_TEXT; | |
655 | fprintf (asmfile, ".stabs \"%s:t", | |
656 | IDENTIFIER_POINTER (DECL_NAME (decl))); | |
657 | ||
658 | current_sym_code = N_LSYM; | |
659 | ||
660 | dbxout_type (TREE_TYPE (decl), 1); | |
661 | dbxout_finish_symbol (); | |
662 | ||
663 | /* Prevent duplicate output of a typedef. */ | |
664 | TREE_ASM_WRITTEN (decl) = 1; | |
665 | break; | |
666 | ||
667 | case PARM_DECL: | |
668 | /* Parm decls go in their own separate chains | |
669 | and are output by dbxout_reg_parms and dbxout_parms. */ | |
670 | abort (); | |
671 | ||
672 | case VAR_DECL: | |
673 | if (DECL_RTL (decl) == 0) | |
674 | return; | |
675 | /* Don't mention a variable that is external. | |
676 | Let the file that defines it describe it. */ | |
677 | if (TREE_EXTERNAL (decl)) | |
678 | break; | |
679 | ||
680 | /* Don't mention a variable at all | |
681 | if it was completely optimized into nothingness. */ | |
682 | if (GET_CODE (DECL_RTL (decl)) == REG | |
683 | && (REGNO (DECL_RTL (decl)) < 0 | |
684 | || REGNO (DECL_RTL (decl)) >= FIRST_PSEUDO_REGISTER)) | |
685 | break; | |
686 | ||
687 | /* The kind-of-variable letter depends on where | |
688 | the variable is and on the scope of its name: | |
689 | G and N_GSYM for static storage and global scope, | |
690 | S for static storage and file scope, | |
691 | V for static storage and local scope, | |
692 | for those two, use N_LCSYM if data is in bss segment, | |
693 | N_STSYM if in data segment, N_FUN otherwise. | |
694 | (We used N_FUN originally, then changed to N_STSYM | |
695 | to please GDB. However, it seems that confused ld. | |
696 | Now GDB has been fixed to like N_FUN, says Kingdon.) | |
697 | no letter at all, and N_LSYM, for auto variable, | |
698 | r and N_RSYM for register variable. */ | |
699 | ||
700 | if (GET_CODE (DECL_RTL (decl)) == MEM | |
701 | && GET_CODE (XEXP (DECL_RTL (decl), 0)) == SYMBOL_REF) | |
702 | { | |
703 | if (TREE_PUBLIC (decl)) | |
704 | { | |
705 | letter = 'G'; | |
706 | current_sym_code = N_GSYM; | |
707 | } | |
708 | else | |
709 | { | |
710 | current_sym_addr = XEXP (DECL_RTL (decl), 0); | |
711 | ||
712 | letter = TREE_PERMANENT (decl) ? 'S' : 'V'; | |
713 | ||
714 | if (!DECL_INITIAL (decl)) | |
715 | current_sym_code = N_LCSYM; | |
716 | else if (TREE_READONLY (decl) && ! TREE_VOLATILE (decl)) | |
717 | /* This is not quite right, but it's the closest | |
718 | of all the codes that Unix defines. */ | |
719 | current_sym_code = N_FUN; | |
720 | else | |
721 | { | |
722 | /* Ultrix `as' seems to need this. */ | |
723 | #ifdef DBX_STATIC_STAB_DATA_SECTION | |
724 | data_section (); | |
725 | #endif | |
726 | current_sym_code = N_STSYM; | |
727 | } | |
728 | } | |
729 | } | |
730 | else if (GET_CODE (DECL_RTL (decl)) == REG) | |
731 | { | |
732 | letter = 'r'; | |
733 | current_sym_code = N_RSYM; | |
734 | current_sym_value = DBX_REGISTER_NUMBER (REGNO (DECL_RTL (decl))); | |
735 | } | |
736 | else if (GET_CODE (DECL_RTL (decl)) == SUBREG) | |
737 | { | |
738 | rtx value = DECL_RTL (decl); | |
739 | int offset = 0; | |
740 | while (GET_CODE (value) == SUBREG) | |
741 | { | |
742 | offset += SUBREG_WORD (value); | |
743 | value = SUBREG_REG (value); | |
744 | } | |
745 | letter = 'r'; | |
746 | current_sym_code = N_RSYM; | |
747 | current_sym_value = DBX_REGISTER_NUMBER (REGNO (value) + offset); | |
748 | } | |
749 | else if (GET_CODE (DECL_RTL (decl)) == MEM | |
750 | && (GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM | |
751 | || (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG | |
752 | && REGNO (XEXP (DECL_RTL (decl), 0)) != FRAME_POINTER_REGNUM))) | |
753 | /* If the value is indirect by memory or by a register | |
754 | that isn't the frame pointer | |
755 | then it means the object is variable-sized and address through | |
756 | that register or stack slot. DBX has no way to represent this | |
757 | so all we can do is output the variable as a pointer. | |
758 | If it's not a parameter, ignore it. | |
759 | (VAR_DECLs like this can be made by integrate.c.) */ | |
760 | { | |
761 | if (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG) | |
762 | { | |
763 | letter = 'r'; | |
764 | current_sym_code = N_RSYM; | |
765 | current_sym_value = DBX_REGISTER_NUMBER (REGNO (XEXP (DECL_RTL (decl), 0))); | |
766 | } | |
767 | else | |
768 | { | |
769 | current_sym_code = N_LSYM; | |
770 | /* DECL_RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))). | |
771 | We want the value of that CONST_INT. */ | |
772 | current_sym_value = INTVAL (XEXP (XEXP (XEXP (DECL_RTL (decl), 0), 0), 1)); | |
773 | } | |
774 | ||
775 | /* Effectively do build_pointer_type, but don't cache this type, | |
776 | since it might be temporary whereas the type it points to | |
777 | might have been saved for inlining. */ | |
778 | type = make_node (POINTER_TYPE); | |
779 | TREE_TYPE (type) = TREE_TYPE (decl); | |
780 | } | |
781 | else if (GET_CODE (DECL_RTL (decl)) == MEM | |
782 | && GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG) | |
783 | { | |
784 | current_sym_code = N_LSYM; | |
785 | current_sym_value = 0; | |
786 | } | |
787 | else if (GET_CODE (DECL_RTL (decl)) == MEM | |
788 | && GET_CODE (XEXP (DECL_RTL (decl), 0)) == PLUS | |
789 | && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 1)) == CONST_INT) | |
790 | { | |
791 | current_sym_code = N_LSYM; | |
792 | /* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...))) | |
793 | We want the value of that CONST_INT. */ | |
794 | current_sym_value = INTVAL (XEXP (XEXP (DECL_RTL (decl), 0), 1)); | |
795 | } | |
796 | else | |
797 | /* Address might be a MEM, when DECL is a variable-sized object. | |
798 | Or it might be const0_rtx, meaning previous passes | |
799 | want us to ignore this variable. */ | |
800 | break; | |
801 | ||
802 | /* Ok, start a symtab entry and output the variable name. */ | |
803 | FORCE_TEXT; | |
804 | fprintf (asmfile, ".stabs \"%s:", | |
805 | IDENTIFIER_POINTER (DECL_NAME (decl))); | |
806 | if (letter) putc (letter, asmfile); | |
807 | dbxout_type (type, 0); | |
808 | dbxout_finish_symbol (); | |
809 | break; | |
810 | } | |
811 | } | |
812 | ||
813 | static void | |
814 | dbxout_finish_symbol () | |
815 | { | |
816 | fprintf (asmfile, "\",%d,0,0,", current_sym_code); | |
817 | if (current_sym_addr) | |
818 | output_addr_const (asmfile, current_sym_addr); | |
819 | else | |
820 | fprintf (asmfile, "%d", current_sym_value); | |
821 | putc ('\n', asmfile); | |
822 | } | |
823 | ||
824 | /* Output definitions of all the decls in a chain. */ | |
825 | ||
826 | static void | |
827 | dbxout_syms (syms) | |
828 | tree syms; | |
829 | { | |
830 | while (syms) | |
831 | { | |
832 | dbxout_symbol (syms, 1); | |
833 | syms = TREE_CHAIN (syms); | |
834 | } | |
835 | } | |
836 | \f | |
837 | /* The following two functions output definitions of function parameters. | |
838 | Each parameter gets a definition locating it in the parameter list. | |
839 | Each parameter that is a register variable gets a second definition | |
840 | locating it in the register. | |
841 | ||
842 | Printing or argument lists in gdb uses the definitions that | |
843 | locate in the parameter list. But reference to the variable in | |
844 | expressions uses preferentially the definition as a register. */ | |
845 | ||
846 | /* Output definitions, referring to storage in the parmlist, | |
847 | of all the parms in PARMS, which is a chain of PARM_DECL nodes. */ | |
848 | ||
849 | static void | |
850 | dbxout_parms (parms) | |
851 | tree parms; | |
852 | { | |
853 | for (; parms; parms = TREE_CHAIN (parms)) | |
854 | { | |
855 | if (DECL_OFFSET (parms) >= 0) | |
856 | { | |
857 | current_sym_code = N_PSYM; | |
858 | current_sym_value = DECL_OFFSET (parms) / BITS_PER_UNIT; | |
859 | current_sym_addr = 0; | |
860 | current_sym_nchars = 2 + strlen (IDENTIFIER_POINTER (DECL_NAME (parms))); | |
861 | ||
862 | FORCE_TEXT; | |
863 | fprintf (asmfile, ".stabs \"%s:p", | |
864 | IDENTIFIER_POINTER (DECL_NAME (parms))); | |
865 | ||
866 | if (GET_CODE (DECL_RTL (parms)) == REG | |
867 | && REGNO (DECL_RTL (parms)) >= 0 | |
868 | && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) | |
869 | dbxout_type (DECL_ARG_TYPE (parms), 0); | |
870 | else | |
871 | { | |
872 | /* This is the case where the parm is passed as an int or double | |
873 | and it is converted to a char, short or float and stored back | |
874 | in the parmlist. In this case, describe the parm | |
875 | with the variable's declared type, and adjust the address | |
876 | if the least significant bytes (which we are using) are not | |
877 | the first ones. */ | |
878 | #ifdef BYTES_BIG_ENDIAN | |
879 | if (TREE_TYPE (parms) != DECL_ARG_TYPE (parms)) | |
880 | current_sym_value += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms))) | |
881 | - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms)))); | |
882 | #endif | |
883 | ||
884 | if (GET_CODE (DECL_RTL (parms)) == MEM | |
885 | && GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS | |
886 | && GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == CONST_INT | |
887 | && INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == current_sym_value) | |
888 | dbxout_type (TREE_TYPE (parms), 0); | |
889 | else | |
890 | { | |
891 | current_sym_value = DECL_OFFSET (parms) / BITS_PER_UNIT; | |
892 | dbxout_type (DECL_ARG_TYPE (parms), 0); | |
893 | } | |
894 | } | |
895 | dbxout_finish_symbol (); | |
896 | } | |
897 | /* Parm was passed in registers. | |
898 | If it lives in a hard register, output a "regparm" symbol | |
899 | for the register it lives in. */ | |
900 | else if (GET_CODE (DECL_RTL (parms)) == REG | |
901 | && REGNO (DECL_RTL (parms)) >= 0 | |
902 | && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER) | |
903 | { | |
904 | current_sym_code = N_RSYM; | |
905 | current_sym_value = DBX_REGISTER_NUMBER (REGNO (DECL_RTL (parms))); | |
906 | current_sym_addr = 0; | |
907 | current_sym_nchars = 2 + strlen (IDENTIFIER_POINTER (DECL_NAME (parms))); | |
908 | ||
909 | FORCE_TEXT; | |
910 | fprintf (asmfile, ".stabs \"%s:P", | |
911 | IDENTIFIER_POINTER (DECL_NAME (parms))); | |
912 | ||
913 | dbxout_type (DECL_ARG_TYPE (parms), 0); | |
914 | dbxout_finish_symbol (); | |
915 | } | |
916 | else if (GET_CODE (DECL_RTL (parms)) == MEM | |
917 | && XEXP (DECL_RTL (parms), 0) != const0_rtx) | |
918 | { | |
919 | current_sym_code = N_LSYM; | |
920 | /* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...))). | |
921 | We want the value of that CONST_INT. */ | |
922 | current_sym_value = INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)); | |
923 | current_sym_addr = 0; | |
924 | current_sym_nchars = 2 + strlen (IDENTIFIER_POINTER (DECL_NAME (parms))); | |
925 | ||
926 | FORCE_TEXT; | |
927 | fprintf (asmfile, ".stabs \"%s:p", | |
928 | IDENTIFIER_POINTER (DECL_NAME (parms))); | |
929 | ||
930 | #if 0 /* This is actually the case in which a parameter | |
931 | is passed in registers but lives on the stack in a local slot. | |
932 | The address we are using is already correct, so don't change it. */ | |
933 | ||
934 | /* This is the case where the parm is passed as an int or double | |
935 | and it is converted to a char, short or float and stored back | |
936 | in the parmlist. In this case, describe the parm | |
937 | with the variable's declared type, and adjust the address | |
938 | if the least significant bytes (which we are using) are not | |
939 | the first ones. */ | |
940 | #ifdef BYTES_BIG_ENDIAN | |
941 | if (TREE_TYPE (parms) != DECL_ARG_TYPE (parms)) | |
942 | current_sym_value += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms))) | |
943 | - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms)))); | |
944 | #endif | |
945 | #endif /* 0 */ | |
946 | ||
947 | dbxout_type (TREE_TYPE (parms), 0); | |
948 | dbxout_finish_symbol (); | |
949 | } | |
950 | } | |
951 | } | |
952 | ||
953 | /* Output definitions, referring to registers, | |
954 | of all the parms in PARMS which are stored in registers during the function. | |
955 | PARMS is a chain of PARM_DECL nodes. */ | |
956 | ||
957 | static void | |
958 | dbxout_reg_parms (parms) | |
959 | tree parms; | |
960 | { | |
961 | while (parms) | |
962 | { | |
963 | /* Report parms that live in registers during the function. */ | |
964 | if (GET_CODE (DECL_RTL (parms)) == REG | |
965 | && REGNO (DECL_RTL (parms)) >= 0 | |
966 | && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER | |
967 | && DECL_OFFSET (parms) >= 0) | |
968 | { | |
969 | current_sym_code = N_RSYM; | |
970 | current_sym_value = DBX_REGISTER_NUMBER (REGNO (DECL_RTL (parms))); | |
971 | current_sym_addr = 0; | |
972 | current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms)); | |
973 | FORCE_TEXT; | |
974 | fprintf (asmfile, ".stabs \"%s:r", | |
975 | IDENTIFIER_POINTER (DECL_NAME (parms))); | |
976 | dbxout_type (TREE_TYPE (parms), 0); | |
977 | dbxout_finish_symbol (); | |
978 | } | |
979 | /* Report parms that live in memory but outside the parmlist. */ | |
980 | else if (GET_CODE (DECL_RTL (parms)) == MEM | |
981 | && GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS | |
982 | && GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == CONST_INT) | |
983 | { | |
984 | int offset = DECL_OFFSET (parms) / BITS_PER_UNIT; | |
985 | /* A parm declared char is really passed as an int, | |
986 | so it occupies the least significant bytes. | |
987 | On a big-endian machine those are not the low-numbered ones. */ | |
988 | #ifdef BYTES_BIG_ENDIAN | |
989 | if (offset != -1 && TREE_TYPE (parms) != DECL_ARG_TYPE (parms)) | |
990 | offset += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms))) | |
991 | - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms)))); | |
992 | #endif | |
993 | if (INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)) != offset) | |
994 | { | |
995 | current_sym_code = N_LSYM; | |
996 | current_sym_value = INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)); | |
997 | current_sym_addr = 0; | |
998 | current_sym_nchars = 2 + IDENTIFIER_LENGTH (DECL_NAME (parms)); | |
999 | FORCE_TEXT; | |
1000 | fprintf (asmfile, ".stabs \"%s:", | |
1001 | IDENTIFIER_POINTER (DECL_NAME (parms))); | |
1002 | dbxout_type (TREE_TYPE (parms), 0); | |
1003 | dbxout_finish_symbol (); | |
1004 | } | |
1005 | } | |
1006 | parms = TREE_CHAIN (parms); | |
1007 | } | |
1008 | } | |
1009 | \f | |
1010 | /* Given a chain of ..._TYPE nodes (as come in a parameter list), | |
1011 | output definitions of those names, in raw form */ | |
1012 | ||
1013 | void | |
1014 | dbxout_args (args) | |
1015 | tree args; | |
1016 | { | |
1017 | while (args) | |
1018 | { | |
1019 | putc (',', asmfile); | |
1020 | dbxout_type (TREE_VALUE (args), 0); | |
1021 | CHARS (1); | |
1022 | args = TREE_CHAIN (args); | |
1023 | } | |
1024 | } | |
1025 | \f | |
1026 | /* Given a chain of ..._TYPE nodes, | |
1027 | find those which have typedef names and output those names. | |
1028 | This is to ensure those types get output. */ | |
1029 | ||
1030 | void | |
1031 | dbxout_types (types) | |
1032 | register tree types; | |
1033 | { | |
1034 | while (types) | |
1035 | { | |
1036 | if (TYPE_NAME (types) | |
1037 | && TREE_CODE (TYPE_NAME (types)) == TYPE_DECL | |
1038 | && ! TREE_ASM_WRITTEN (TYPE_NAME (types))) | |
1039 | dbxout_symbol (TYPE_NAME (types), 1); | |
1040 | types = TREE_CHAIN (types); | |
1041 | } | |
1042 | } | |
1043 | ||
1044 | /* Output the tags (struct, union and enum definitions with names) for a block, | |
1045 | given a list of them (a chain of TREE_LIST nodes) in TAGS. | |
1046 | We must check to include those that have been mentioned already with | |
1047 | only a cross-reference. */ | |
1048 | ||
1049 | void | |
1050 | dbxout_tags (tags) | |
1051 | tree tags; | |
1052 | { | |
1053 | register tree link; | |
1054 | for (link = tags; link; link = TREE_CHAIN (link)) | |
1055 | { | |
1056 | register tree type = TYPE_MAIN_VARIANT (TREE_VALUE (link)); | |
1057 | if (TREE_PURPOSE (link) != 0 | |
1058 | && ! TREE_ASM_WRITTEN (link) | |
1059 | && TYPE_SIZE (type) != 0) | |
1060 | { | |
1061 | TREE_ASM_WRITTEN (link) = 1; | |
1062 | current_sym_code = N_LSYM; | |
1063 | current_sym_value = 0; | |
1064 | current_sym_addr = 0; | |
1065 | current_sym_nchars = 2 + IDENTIFIER_LENGTH (TREE_PURPOSE (link)); | |
1066 | ||
1067 | FORCE_TEXT; | |
1068 | fprintf (asmfile, ".stabs \"%s:T", | |
1069 | IDENTIFIER_POINTER (TREE_PURPOSE (link))); | |
1070 | dbxout_type (type, 1); | |
1071 | dbxout_finish_symbol (); | |
1072 | } | |
1073 | } | |
1074 | } | |
1075 | \f | |
1076 | /* Output everything about a symbol block (that is to say, a LET_STMT node | |
1077 | that represents a scope level), | |
1078 | including recursive output of contained blocks. | |
1079 | ||
1080 | STMT is the LET_STMT node. | |
1081 | DEPTH is its depth within containing symbol blocks. | |
1082 | ARGS is usually zero; but for the outermost block of the | |
1083 | body of a function, it is a chain of PARM_DECLs for the function parameters. | |
1084 | We output definitions of all the register parms | |
1085 | as if they were local variables of that block. | |
1086 | ||
1087 | Actually, STMT may be several statements chained together. | |
1088 | We handle them all in sequence. */ | |
1089 | ||
1090 | static void | |
1091 | dbxout_block (stmt, depth, args) | |
1092 | register tree stmt; | |
1093 | int depth; | |
1094 | tree args; | |
1095 | { | |
1096 | int blocknum; | |
1097 | ||
1098 | while (stmt) | |
1099 | { | |
1100 | switch (TREE_CODE (stmt)) | |
1101 | { | |
1102 | case COMPOUND_STMT: | |
1103 | case LOOP_STMT: | |
1104 | dbxout_block (STMT_BODY (stmt), depth, 0); | |
1105 | break; | |
1106 | ||
1107 | case IF_STMT: | |
1108 | dbxout_block (STMT_THEN (stmt), depth, 0); | |
1109 | dbxout_block (STMT_ELSE (stmt), depth, 0); | |
1110 | break; | |
1111 | ||
1112 | case LET_STMT: | |
1113 | /* Ignore LET_STMTs for blocks never really used to make RTL. */ | |
1114 | if (! TREE_USED (stmt)) | |
1115 | break; | |
1116 | /* In dbx format, the syms of a block come before the N_LBRAC. */ | |
1117 | dbxout_tags (STMT_TYPE_TAGS (stmt)); | |
1118 | dbxout_syms (STMT_VARS (stmt)); | |
1119 | if (args) | |
1120 | dbxout_reg_parms (args); | |
1121 | ||
1122 | /* Now output an N_LBRAC symbol to represent the beginning of | |
1123 | the block. Use the block's tree-walk order to generate | |
1124 | the assembler symbols LBBn and LBEn | |
1125 | that final will define around the code in this block. */ | |
1126 | if (depth > 0) | |
1127 | { | |
1128 | char buf[20]; | |
1129 | blocknum = next_block_number++; | |
1130 | ASM_GENERATE_INTERNAL_LABEL (buf, "LBB", blocknum); | |
1131 | fprintf (asmfile, ".stabn %d,0,0,", N_LBRAC); | |
1132 | assemble_name (asmfile, buf); | |
1133 | fprintf (asmfile, "\n"); | |
1134 | } | |
1135 | ||
1136 | /* Output the subblocks. */ | |
1137 | dbxout_block (STMT_SUBBLOCKS (stmt), depth + 1, 0); | |
1138 | ||
1139 | /* Refer to the marker for the end of the block. */ | |
1140 | if (depth > 0) | |
1141 | { | |
1142 | char buf[20]; | |
1143 | ASM_GENERATE_INTERNAL_LABEL (buf, "LBE", blocknum); | |
1144 | fprintf (asmfile, ".stabn %d,0,0,", N_RBRAC); | |
1145 | assemble_name (asmfile, buf); | |
1146 | fprintf (asmfile, "\n"); | |
1147 | } | |
1148 | } | |
1149 | stmt = TREE_CHAIN (stmt); | |
1150 | } | |
1151 | } | |
1152 | ||
1153 | /* Output dbx data for a function definition. | |
1154 | This includes a definition of the function name itself (a symbol), | |
1155 | definitions of the parameters (locating them in the parameter list) | |
1156 | and then output the block that makes up the function's body | |
1157 | (including all the auto variables of the function). */ | |
1158 | ||
1159 | void | |
1160 | dbxout_function (decl) | |
1161 | tree decl; | |
1162 | { | |
1163 | dbxout_symbol (decl, 0); | |
1164 | dbxout_parms (DECL_ARGUMENTS (decl)); | |
1165 | dbxout_block (DECL_INITIAL (decl), 0, DECL_ARGUMENTS (decl)); | |
1166 | ||
1167 | /* If we made any temporary types in this fn that weren't | |
1168 | output, output them now. */ | |
1169 | dbxout_types (get_temporary_types ()); | |
1170 | } | |
1171 | \f | |
1172 | #else /* not DBX_DEBUGGING_INFO */ | |
1173 | ||
1174 | void | |
1175 | dbxout_init (asm_file, input_file_name) | |
1176 | FILE *asm_file; | |
1177 | char *input_file_name; | |
1178 | {} | |
1179 | ||
1180 | void | |
1181 | dbxout_symbol (decl, local) | |
1182 | tree decl; | |
1183 | int local; | |
1184 | {} | |
1185 | ||
1186 | void | |
1187 | dbxout_types (types) | |
1188 | register tree types; | |
1189 | {} | |
1190 | ||
1191 | void | |
1192 | dbxout_tags (tags) | |
1193 | tree tags; | |
1194 | {} | |
1195 | ||
1196 | void | |
1197 | dbxout_function (decl) | |
1198 | tree decl; | |
1199 | {} | |
1200 | ||
1201 | #endif /* DBX_DEBUGGING_INFO */ |