1 | /* Output VMS debug format symbol table information from GCC. |
2 | Copyright (C) 1987-2023 Free Software Foundation, Inc. |
3 | Contributed by Douglas B. Rupp (rupp@gnat.com). |
4 | Updated by Bernard W. Giroud (bgiroud@users.sourceforge.net). |
5 | |
6 | This file is part of GCC. |
7 | |
8 | GCC is free software; you can redistribute it and/or modify it under |
9 | the terms of the GNU General Public License as published by the Free |
10 | Software Foundation; either version 3, or (at your option) any later |
11 | version. |
12 | |
13 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
14 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
16 | for more details. |
17 | |
18 | You should have received a copy of the GNU General Public License |
19 | along with GCC; see the file COPYING3. If not see |
20 | <http://www.gnu.org/licenses/>. */ |
21 | |
22 | #include "config.h" |
23 | #include "system.h" |
24 | #include "coretypes.h" |
25 | #include "tm.h" |
26 | |
27 | #ifdef VMS_DEBUGGING_INFO |
28 | #include "alias.h" |
29 | #include "tree.h" |
30 | #include "varasm.h" |
31 | #include "version.h" |
32 | #include "flags.h" |
33 | #include "rtl.h" |
34 | #include "output.h" |
35 | #include "vmsdbg.h" |
36 | #include "debug.h" |
37 | #include "langhooks.h" |
38 | #include "function.h" |
39 | #include "target.h" |
40 | #include "file-prefix-map.h" /* remap_debug_filename() */ |
41 | |
42 | /* Difference in seconds between the VMS Epoch and the Unix Epoch */ |
43 | static const long long vms_epoch_offset = 3506716800ll; |
44 | |
45 | int vms_file_stats_name (const char *, long long *, long *, char *, int *); |
46 | |
47 | /* NOTE: In the comments in this file, many references are made to "Debug |
48 | Symbol Table". This term is abbreviated as `DST' throughout the remainder |
49 | of this file. */ |
50 | |
51 | typedef struct dst_line_info_struct *dst_line_info_ref; |
52 | |
53 | /* Each entry in the line_info_table maintains the file and |
54 | line number associated with the label generated for that |
55 | entry. The label gives the PC value associated with |
56 | the line number entry. */ |
57 | typedef struct dst_line_info_struct |
58 | { |
59 | unsigned long dst_file_num; |
60 | unsigned long dst_line_num; |
61 | } |
62 | dst_line_info_entry; |
63 | |
64 | typedef struct dst_file_info_struct *dst_file_info_ref; |
65 | |
66 | typedef struct dst_file_info_struct |
67 | { |
68 | char *file_name; |
69 | unsigned int max_line; |
70 | unsigned int listing_line_start; |
71 | long long cdt; |
72 | long ebk; |
73 | short ffb; |
74 | char rfo; |
75 | } |
76 | dst_file_info_entry; |
77 | |
78 | /* Maximum size (in bytes) of an artificially generated label. */ |
79 | #define MAX_ARTIFICIAL_LABEL_BYTES 30 |
80 | |
81 | /* Make sure we know the sizes of the various types debug can describe. These |
82 | are only defaults. If the sizes are different for your target, you should |
83 | override these values by defining the appropriate symbols in your tm.h |
84 | file. */ |
85 | #ifndef PTR_SIZE |
86 | #define PTR_SIZE 4 /* Must be 32 bits for VMS debug info */ |
87 | #endif |
88 | |
89 | /* Pointer to a structure of filenames referenced by this compilation unit. */ |
90 | static dst_file_info_ref file_info_table; |
91 | |
92 | /* Total number of entries in the table (i.e. array) pointed to by |
93 | `file_info_table'. This is the *total* and includes both used and unused |
94 | slots. */ |
95 | static unsigned int file_info_table_allocated; |
96 | |
97 | /* Number of entries in the file_info_table which are actually in use. */ |
98 | static unsigned int file_info_table_in_use; |
99 | |
100 | /* Size (in elements) of increments by which we may expand the filename |
101 | table. */ |
102 | #define FILE_TABLE_INCREMENT 64 |
103 | |
104 | typedef char *char_p; |
105 | |
106 | static vec<char_p> funcnam_table; |
107 | static vec<unsigned> funcnum_table; |
108 | #define FUNC_TABLE_INITIAL 256 |
109 | |
110 | /* Local pointer to the name of the main input file. Initialized in |
111 | vmsdbgout_init. */ |
112 | static const char *primary_filename; |
113 | |
114 | static char *module_producer; |
115 | static unsigned int module_language; |
116 | |
117 | /* A pointer to the base of a table that contains line information |
118 | for each source code line in .text in the compilation unit. */ |
119 | static dst_line_info_ref line_info_table; |
120 | |
121 | /* Number of elements currently allocated for line_info_table. */ |
122 | static unsigned int line_info_table_allocated; |
123 | |
124 | /* Number of elements in line_info_table currently in use. */ |
125 | static unsigned int line_info_table_in_use; |
126 | |
127 | /* Size (in elements) of increments by which we may expand line_info_table. */ |
128 | #define LINE_INFO_TABLE_INCREMENT 1024 |
129 | |
130 | /* Forward declarations for functions defined in this file. */ |
131 | static char *full_name (const char *); |
132 | static unsigned int lookup_filename (const char *); |
133 | static int write_debug_header (DST_HEADER *, const char *, int); |
134 | static int write_debug_addr (const char *, const char *, int); |
135 | static int write_debug_data1 (unsigned int, const char *, int); |
136 | static int write_debug_data2 (unsigned int, const char *, int); |
137 | static int write_debug_data4 (unsigned long, const char *, int); |
138 | static int write_debug_data8 (unsigned long long, const char *, int); |
139 | static int write_debug_delta4 (const char *, const char *, const char *, int); |
140 | static int write_debug_string (const char *, const char *, int); |
141 | static int write_modbeg (int); |
142 | static int write_modend (int); |
143 | static int write_rtnbeg (int, int); |
144 | static int write_rtnend (int, int); |
145 | static int write_pclines (int); |
146 | static int write_srccorr (int, dst_file_info_entry, int); |
147 | static int write_srccorrs (int); |
148 | |
149 | static void vmsdbgout_init (const char *); |
150 | static void vmsdbgout_finish (const char *); |
151 | static void vmsdbgout_early_finish (const char *); |
152 | static void vmsdbgout_assembly_start (void); |
153 | static void vmsdbgout_define (unsigned int, const char *); |
154 | static void vmsdbgout_undef (unsigned int, const char *); |
155 | static void vmsdbgout_start_source_file (unsigned int, const char *); |
156 | static void vmsdbgout_end_source_file (unsigned int); |
157 | static void vmsdbgout_begin_block (unsigned int, unsigned int); |
158 | static void vmsdbgout_end_block (unsigned int, unsigned int); |
159 | static bool vmsdbgout_ignore_block (const_tree); |
160 | static void vmsdbgout_source_line (unsigned int, unsigned int, const char *, |
161 | int, bool); |
162 | static void vmsdbgout_write_source_line (unsigned, const char *, int , bool); |
163 | static void vmsdbgout_begin_prologue (unsigned int, unsigned int, |
164 | const char *); |
165 | static void vmsdbgout_end_prologue (unsigned int, const char *); |
166 | static void vmsdbgout_end_function (unsigned int); |
167 | static void vmsdbgout_begin_epilogue (unsigned int, const char *); |
168 | static void vmsdbgout_end_epilogue (unsigned int, const char *); |
169 | static void vmsdbgout_begin_function (tree); |
170 | static void vmsdbgout_function_decl (tree); |
171 | static void vmsdbgout_early_global_decl (tree); |
172 | static void vmsdbgout_late_global_decl (tree); |
173 | static void vmsdbgout_type_decl (tree, int); |
174 | static void vmsdbgout_abstract_function (tree); |
175 | |
176 | /* The debug hooks structure. */ |
177 | |
178 | const struct gcc_debug_hooks vmsdbg_debug_hooks |
179 | = {vmsdbgout_init, |
180 | vmsdbgout_finish, |
181 | vmsdbgout_early_finish, |
182 | vmsdbgout_assembly_start, |
183 | vmsdbgout_define, |
184 | vmsdbgout_undef, |
185 | vmsdbgout_start_source_file, |
186 | vmsdbgout_end_source_file, |
187 | vmsdbgout_begin_block, |
188 | vmsdbgout_end_block, |
189 | vmsdbgout_ignore_block, |
190 | vmsdbgout_source_line, |
191 | debug_nothing_int_int_charstar, /* set_ignored_loc */ |
192 | vmsdbgout_begin_prologue, |
193 | vmsdbgout_end_prologue, |
194 | vmsdbgout_begin_epilogue, |
195 | vmsdbgout_end_epilogue, |
196 | vmsdbgout_begin_function, |
197 | vmsdbgout_end_function, |
198 | debug_nothing_tree, /* register_main_translation_unit */ |
199 | vmsdbgout_function_decl, |
200 | vmsdbgout_early_global_decl, |
201 | vmsdbgout_late_global_decl, |
202 | vmsdbgout_type_decl, /* type_decl */ |
203 | debug_nothing_tree_tree_tree_bool_bool, /* imported_module_or_decl */ |
204 | debug_false_tree_charstarstar_uhwistar, /* die_ref_for_decl */ |
205 | debug_nothing_tree_charstar_uhwi, /* register_external_die */ |
206 | debug_nothing_tree, /* deferred_inline_function */ |
207 | vmsdbgout_abstract_function, |
208 | debug_nothing_rtx_code_label, /* label */ |
209 | debug_nothing_int, /* handle_pch */ |
210 | debug_nothing_rtx_insn, /* var_location */ |
211 | debug_nothing_tree, /* inline_entry */ |
212 | debug_nothing_tree, /* size_function */ |
213 | debug_nothing_void, /* switch_text_section */ |
214 | debug_nothing_tree_tree, /* set_name */ |
215 | 0, /* start_end_main_source_file */ |
216 | TYPE_SYMTAB_IS_ADDRESS /* tree_type_symtab_field */ |
217 | }; |
218 | |
219 | /* Definitions of defaults for assembler-dependent names of various |
220 | pseudo-ops and section names. */ |
221 | #define VMS_UNALIGNED_SHORT_ASM_OP ".word" |
222 | #define VMS_UNALIGNED_INT_ASM_OP ".long" |
223 | #define VMS_UNALIGNED_LONG_ASM_OP ".long" |
224 | #define VMS_UNALIGNED_DOUBLE_INT_ASM_OP ".quad" |
225 | |
226 | #define VMS_ASM_BYTE_OP ".byte" |
227 | |
228 | #define NUMBYTES(I) ((I) < 256 ? 1 : (I) < 65536 ? 2 : 4) |
229 | |
230 | #define NUMBYTES0(I) ((I) < 128 ? 0 : (I) < 65536 ? 2 : 4) |
231 | |
232 | #ifndef UNALIGNED_PTR_ASM_OP |
233 | #define UNALIGNED_PTR_ASM_OP \ |
234 | (PTR_SIZE == 8 ? VMS_UNALIGNED_DOUBLE_INT_ASM_OP : VMS_UNALIGNED_INT_ASM_OP) |
235 | #endif |
236 | |
237 | #ifndef UNALIGNED_OFFSET_ASM_OP |
238 | #define UNALIGNED_OFFSET_ASM_OP(OFFSET) \ |
239 | (NUMBYTES (OFFSET) == 4 \ |
240 | ? VMS_UNALIGNED_LONG_ASM_OP \ |
241 | : (NUMBYTES (OFFSET) == 2 ? VMS_UNALIGNED_SHORT_ASM_OP : VMS_ASM_BYTE_OP)) |
242 | #endif |
243 | |
244 | /* Definitions of defaults for formats and names of various special |
245 | (artificial) labels which may be generated within this file (when the -g |
246 | options is used and VMS_DEBUGGING_INFO is in effect. If necessary, these |
247 | may be overridden from within the tm.h file, but typically, overriding these |
248 | defaults is unnecessary. */ |
249 | |
250 | static char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES]; |
251 | |
252 | #ifndef TEXT_END_LABEL |
253 | #define TEXT_END_LABEL "Lvetext" |
254 | #endif |
255 | #ifndef FUNC_BEGIN_LABEL |
256 | #define FUNC_BEGIN_LABEL "LVFB" |
257 | #endif |
258 | #ifndef FUNC_PROLOG_LABEL |
259 | #define FUNC_PROLOG_LABEL "LVFP" |
260 | #endif |
261 | #ifndef FUNC_EPILOG_LABEL |
262 | #define FUNC_EPILOG_LABEL "LVEB" |
263 | #endif |
264 | #ifndef FUNC_END_LABEL |
265 | #define FUNC_END_LABEL "LVFE" |
266 | #endif |
267 | #ifndef BLOCK_BEGIN_LABEL |
268 | #define BLOCK_BEGIN_LABEL "LVBB" |
269 | #endif |
270 | #ifndef BLOCK_END_LABEL |
271 | #define BLOCK_END_LABEL "LVBE" |
272 | #endif |
273 | #ifndef LINE_CODE_LABEL |
274 | #define LINE_CODE_LABEL "LVM" |
275 | #endif |
276 | |
277 | #ifndef ASM_OUTPUT_DEBUG_DELTA2 |
278 | #define ASM_OUTPUT_DEBUG_DELTA2(FILE,LABEL1,LABEL2) \ |
279 | do \ |
280 | { \ |
281 | fprintf ((FILE), "\t%s\t", VMS_UNALIGNED_SHORT_ASM_OP); \ |
282 | assemble_name (FILE, LABEL1); \ |
283 | fprintf (FILE, "-"); \ |
284 | assemble_name (FILE, LABEL2); \ |
285 | } \ |
286 | while (0) |
287 | #endif |
288 | |
289 | #ifndef ASM_OUTPUT_DEBUG_DELTA4 |
290 | #define ASM_OUTPUT_DEBUG_DELTA4(FILE,LABEL1,LABEL2) \ |
291 | do \ |
292 | { \ |
293 | fprintf ((FILE), "\t%s\t", VMS_UNALIGNED_INT_ASM_OP); \ |
294 | assemble_name (FILE, LABEL1); \ |
295 | fprintf (FILE, "-"); \ |
296 | assemble_name (FILE, LABEL2); \ |
297 | } \ |
298 | while (0) |
299 | #endif |
300 | |
301 | #ifndef ASM_OUTPUT_DEBUG_ADDR_DELTA |
302 | #define ASM_OUTPUT_DEBUG_ADDR_DELTA(FILE,LABEL1,LABEL2) \ |
303 | do \ |
304 | { \ |
305 | fprintf ((FILE), "\t%s\t", UNALIGNED_PTR_ASM_OP); \ |
306 | assemble_name (FILE, LABEL1); \ |
307 | fprintf (FILE, "-"); \ |
308 | assemble_name (FILE, LABEL2); \ |
309 | } \ |
310 | while (0) |
311 | #endif |
312 | |
313 | #ifndef ASM_OUTPUT_DEBUG_ADDR |
314 | #define ASM_OUTPUT_DEBUG_ADDR(FILE,LABEL) \ |
315 | do \ |
316 | { \ |
317 | fprintf ((FILE), "\t%s\t", UNALIGNED_PTR_ASM_OP); \ |
318 | assemble_name (FILE, LABEL); \ |
319 | } \ |
320 | while (0) |
321 | #endif |
322 | |
323 | #ifndef ASM_OUTPUT_DEBUG_ADDR_CONST |
324 | #define ASM_OUTPUT_DEBUG_ADDR_CONST(FILE,ADDR) \ |
325 | fprintf ((FILE), "\t%s\t%s", UNALIGNED_PTR_ASM_OP, (ADDR)) |
326 | #endif |
327 | |
328 | #ifndef ASM_OUTPUT_DEBUG_DATA1 |
329 | #define ASM_OUTPUT_DEBUG_DATA1(FILE,VALUE) \ |
330 | fprintf ((FILE), "\t%s\t%#x", VMS_ASM_BYTE_OP, (unsigned char) VALUE) |
331 | #endif |
332 | |
333 | #ifndef ASM_OUTPUT_DEBUG_DATA2 |
334 | #define ASM_OUTPUT_DEBUG_DATA2(FILE,VALUE) \ |
335 | fprintf ((FILE), "\t%s\t%#x", VMS_UNALIGNED_SHORT_ASM_OP, \ |
336 | (unsigned short) VALUE) |
337 | #endif |
338 | |
339 | #ifndef ASM_OUTPUT_DEBUG_DATA4 |
340 | #define ASM_OUTPUT_DEBUG_DATA4(FILE,VALUE) \ |
341 | fprintf ((FILE), "\t%s\t%#lx", VMS_UNALIGNED_INT_ASM_OP, \ |
342 | (unsigned long) VALUE) |
343 | #endif |
344 | |
345 | #ifndef ASM_OUTPUT_DEBUG_DATA |
346 | #define ASM_OUTPUT_DEBUG_DATA(FILE,VALUE) \ |
347 | fprintf ((FILE), "\t%s\t%#lx", UNALIGNED_OFFSET_ASM_OP (VALUE), VALUE) |
348 | #endif |
349 | |
350 | #ifndef ASM_OUTPUT_DEBUG_ADDR_DATA |
351 | #define ASM_OUTPUT_DEBUG_ADDR_DATA(FILE,VALUE) \ |
352 | fprintf ((FILE), "\t%s\t%#lx", UNALIGNED_PTR_ASM_OP, \ |
353 | (unsigned long) VALUE) |
354 | #endif |
355 | |
356 | #ifndef ASM_OUTPUT_DEBUG_DATA8 |
357 | #define ASM_OUTPUT_DEBUG_DATA8(FILE,VALUE) \ |
358 | fprintf ((FILE), "\t%s\t%#llx", VMS_UNALIGNED_DOUBLE_INT_ASM_OP, \ |
359 | (unsigned long long) VALUE) |
360 | #endif |
361 | |
362 | /* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing |
363 | newline is produced. When flag_verbose_asm is asserted, we add commentary |
364 | at the end of the line, so we must avoid output of a newline here. */ |
365 | #ifndef ASM_OUTPUT_DEBUG_STRING |
366 | #define ASM_OUTPUT_DEBUG_STRING(FILE,P) \ |
367 | do \ |
368 | { \ |
369 | int slen = strlen (P); \ |
370 | const char *p = (P); \ |
371 | int i; \ |
372 | fprintf (FILE, "\t.ascii \""); \ |
373 | for (i = 0; i < slen; i++) \ |
374 | { \ |
375 | int c = p[i]; \ |
376 | if (c == '\"' || c == '\\') \ |
377 | putc ('\\', FILE); \ |
378 | if (c >= ' ' && c < 0177) \ |
379 | putc (c, FILE); \ |
380 | else \ |
381 | fprintf (FILE, "\\%o", c); \ |
382 | } \ |
383 | fprintf (FILE, "\""); \ |
384 | } \ |
385 | while (0) |
386 | #endif |
387 | |
388 | /* Convert a reference to the assembler name of a C-level name. This |
389 | macro has the same effect as ASM_OUTPUT_LABELREF, but copies to |
390 | a string rather than writing to a file. */ |
391 | #ifndef ASM_NAME_TO_STRING |
392 | #define ASM_NAME_TO_STRING(STR, NAME) \ |
393 | do \ |
394 | { \ |
395 | if ((NAME)[0] == '*') \ |
396 | strcpy (STR, NAME+1); \ |
397 | else \ |
398 | strcpy (STR, NAME); \ |
399 | } \ |
400 | while (0) |
401 | #endif |
402 | |
403 | |
404 | /* Output the debug header HEADER. Also output COMMENT if flag_verbose_asm is |
405 | set. Return the header size. Just return the size if DOSIZEONLY is |
406 | nonzero. */ |
407 | |
408 | static int |
409 | write_debug_header (DST_HEADER *header, const char *comment, int dosizeonly) |
410 | { |
411 | if (!dosizeonly) |
412 | { |
413 | ASM_OUTPUT_DEBUG_DATA2 (asm_out_file, |
414 | header->dst__header_length.dst_w_length); |
415 | |
416 | if (flag_verbose_asm) |
417 | fprintf (asm_out_file, "\t%s record length" , ASM_COMMENT_START); |
418 | fputc ('\n', asm_out_file); |
419 | |
420 | ASM_OUTPUT_DEBUG_DATA2 (asm_out_file, |
421 | header->dst__header_type.dst_w_type); |
422 | |
423 | if (flag_verbose_asm) |
424 | fprintf (asm_out_file, "\t%s record type (%s)" , ASM_COMMENT_START, |
425 | comment); |
426 | |
427 | fputc ('\n', asm_out_file); |
428 | } |
429 | |
430 | return 4; |
431 | } |
432 | |
433 | /* Output the address of SYMBOL. Also output COMMENT if flag_verbose_asm is |
434 | set. Return the address size. Just return the size if DOSIZEONLY is |
435 | nonzero. */ |
436 | |
437 | static int |
438 | write_debug_addr (const char *symbol, const char *comment, int dosizeonly) |
439 | { |
440 | if (!dosizeonly) |
441 | { |
442 | ASM_OUTPUT_DEBUG_ADDR (asm_out_file, symbol); |
443 | if (flag_verbose_asm) |
444 | fprintf (asm_out_file, "\t%s %s" , ASM_COMMENT_START, comment); |
445 | fputc ('\n', asm_out_file); |
446 | } |
447 | |
448 | return PTR_SIZE; |
449 | } |
450 | |
451 | /* Output the single byte DATA1. Also output COMMENT if flag_verbose_asm is |
452 | set. Return the data size. Just return the size if DOSIZEONLY is |
453 | nonzero. */ |
454 | |
455 | static int |
456 | write_debug_data1 (unsigned int data1, const char *comment, int dosizeonly) |
457 | { |
458 | if (!dosizeonly) |
459 | { |
460 | ASM_OUTPUT_DEBUG_DATA1 (asm_out_file, data1); |
461 | if (flag_verbose_asm) |
462 | fprintf (asm_out_file, "\t%s %s" , ASM_COMMENT_START, comment); |
463 | fputc ('\n', asm_out_file); |
464 | } |
465 | |
466 | return 1; |
467 | } |
468 | |
469 | /* Output the single word DATA2. Also output COMMENT if flag_verbose_asm is |
470 | set. Return the data size. Just return the size if DOSIZEONLY is |
471 | nonzero. */ |
472 | |
473 | static int |
474 | write_debug_data2 (unsigned int data2, const char *comment, int dosizeonly) |
475 | { |
476 | if (!dosizeonly) |
477 | { |
478 | ASM_OUTPUT_DEBUG_DATA2 (asm_out_file, data2); |
479 | if (flag_verbose_asm) |
480 | fprintf (asm_out_file, "\t%s %s" , ASM_COMMENT_START, comment); |
481 | fputc ('\n', asm_out_file); |
482 | } |
483 | |
484 | return 2; |
485 | } |
486 | |
487 | /* Output double word DATA4. Also output COMMENT if flag_verbose_asm is set. |
488 | Return the data size. Just return the size if DOSIZEONLY is nonzero. */ |
489 | |
490 | static int |
491 | write_debug_data4 (unsigned long data4, const char *comment, int dosizeonly) |
492 | { |
493 | if (!dosizeonly) |
494 | { |
495 | ASM_OUTPUT_DEBUG_DATA4 (asm_out_file, data4); |
496 | if (flag_verbose_asm) |
497 | fprintf (asm_out_file, "\t%s %s" , ASM_COMMENT_START, comment); |
498 | fputc ('\n', asm_out_file); |
499 | } |
500 | |
501 | return 4; |
502 | } |
503 | |
504 | /* Output quad word DATA8. Also output COMMENT if flag_verbose_asm is set. |
505 | Return the data size. Just return the size if DOSIZEONLY is nonzero. */ |
506 | |
507 | static int |
508 | write_debug_data8 (unsigned long long data8, const char *comment, |
509 | int dosizeonly) |
510 | { |
511 | if (!dosizeonly) |
512 | { |
513 | ASM_OUTPUT_DEBUG_DATA8 (asm_out_file, data8); |
514 | if (flag_verbose_asm) |
515 | fprintf (asm_out_file, "\t%s %s" , ASM_COMMENT_START, comment); |
516 | fputc ('\n', asm_out_file); |
517 | } |
518 | |
519 | return 8; |
520 | } |
521 | |
522 | /* Output the difference between LABEL1 and LABEL2. Also output COMMENT if |
523 | flag_verbose_asm is set. Return the data size. Just return the size if |
524 | DOSIZEONLY is nonzero. */ |
525 | |
526 | static int |
527 | write_debug_delta4 (const char *label1, const char *label2, |
528 | const char *comment, int dosizeonly) |
529 | { |
530 | if (!dosizeonly) |
531 | { |
532 | ASM_OUTPUT_DEBUG_DELTA4 (asm_out_file, label1, label2); |
533 | if (flag_verbose_asm) |
534 | fprintf (asm_out_file, "\t%s %s" , ASM_COMMENT_START, comment); |
535 | fputc ('\n', asm_out_file); |
536 | } |
537 | |
538 | return 4; |
539 | } |
540 | |
541 | /* Output a character string STRING. Also write COMMENT if flag_verbose_asm is |
542 | set. Return the string length. Just return the length if DOSIZEONLY is |
543 | nonzero. */ |
544 | |
545 | static int |
546 | write_debug_string (const char *string, const char *comment, int dosizeonly) |
547 | { |
548 | if (!dosizeonly) |
549 | { |
550 | ASM_OUTPUT_DEBUG_STRING (asm_out_file, string); |
551 | if (flag_verbose_asm) |
552 | fprintf (asm_out_file, "\t%s %s" , ASM_COMMENT_START, comment); |
553 | fputc ('\n', asm_out_file); |
554 | } |
555 | |
556 | return strlen (string); |
557 | } |
558 | |
559 | /* Output a module begin header and return the header size. Just return the |
560 | size if DOSIZEONLY is nonzero. */ |
561 | |
562 | static int |
563 | write_modbeg (int dosizeonly) |
564 | { |
565 | DST_MODULE_BEGIN modbeg; |
566 | DST_MB_TRLR mb_trlr; |
567 | int i; |
568 | char *module_name, *m; |
569 | int modnamelen; |
570 | int prodnamelen; |
571 | int totsize = 0; |
572 | |
573 | /* Assumes primary filename has Unix syntax file spec. */ |
574 | module_name = xstrdup (lbasename (primary_filename)); |
575 | |
576 | m = strrchr (module_name, '.'); |
577 | if (m) |
578 | *m = 0; |
579 | |
580 | modnamelen = strlen (module_name); |
581 | for (i = 0; i < modnamelen; i++) |
582 | module_name[i] = TOUPPER (module_name[i]); |
583 | |
584 | prodnamelen = strlen (module_producer); |
585 | |
586 | modbeg.dst_a_modbeg_header.dst__header_length.dst_w_length |
587 | = DST_K_MODBEG_SIZE + modnamelen + DST_K_MB_TRLR_SIZE + prodnamelen - 1; |
588 | modbeg.dst_a_modbeg_header.dst__header_type.dst_w_type = DST_K_MODBEG; |
589 | modbeg.dst_b_modbeg_flags.dst_v_modbeg_hide = 0; |
590 | modbeg.dst_b_modbeg_flags.dst_v_modbeg_version = 1; |
591 | modbeg.dst_b_modbeg_flags.dst_v_modbeg_unused = 0; |
592 | modbeg.dst_b_modbeg_unused = 0; |
593 | modbeg.dst_l_modbeg_language = (DST_LANGUAGE) module_language; |
594 | modbeg.dst_w_version_major = DST_K_VERSION_MAJOR; |
595 | modbeg.dst_w_version_minor = DST_K_VERSION_MINOR; |
596 | modbeg.dst_b_modbeg_name = strlen (module_name); |
597 | |
598 | mb_trlr.dst_b_compiler = strlen (module_producer); |
599 | |
600 | totsize += write_debug_header (&modbeg.dst_a_modbeg_header, |
601 | "modbeg" , dosizeonly); |
602 | totsize += write_debug_data1 (*((char *) &modbeg.dst_b_modbeg_flags), |
603 | "flags" , dosizeonly); |
604 | totsize += write_debug_data1 (modbeg.dst_b_modbeg_unused, |
605 | "unused" , dosizeonly); |
606 | totsize += write_debug_data4 (modbeg.dst_l_modbeg_language, |
607 | "language" , dosizeonly); |
608 | totsize += write_debug_data2 (modbeg.dst_w_version_major, |
609 | "DST major version" , dosizeonly); |
610 | totsize += write_debug_data2 (modbeg.dst_w_version_minor, |
611 | "DST minor version" , dosizeonly); |
612 | totsize += write_debug_data1 (modbeg.dst_b_modbeg_name, |
613 | "length of module name" , dosizeonly); |
614 | totsize += write_debug_string (module_name, "module name" , dosizeonly); |
615 | totsize += write_debug_data1 (mb_trlr.dst_b_compiler, |
616 | "length of compiler name" , dosizeonly); |
617 | totsize += write_debug_string (module_producer, "compiler name" , dosizeonly); |
618 | |
619 | return totsize; |
620 | } |
621 | |
622 | /* Output a module end trailer and return the trailer size. Just return |
623 | the size if DOSIZEONLY is nonzero. */ |
624 | |
625 | static int |
626 | write_modend (int dosizeonly) |
627 | { |
628 | DST_MODULE_END modend; |
629 | int totsize = 0; |
630 | |
631 | modend.dst_a_modend_header.dst__header_length.dst_w_length |
632 | = DST_K_MODEND_SIZE - 1; |
633 | modend.dst_a_modend_header.dst__header_type.dst_w_type = DST_K_MODEND; |
634 | |
635 | totsize += write_debug_header (&modend.dst_a_modend_header, "modend" , |
636 | dosizeonly); |
637 | |
638 | return totsize; |
639 | } |
640 | |
641 | /* Output a routine begin header routine RTNNUM and return the header size. |
642 | Just return the size if DOSIZEONLY is nonzero. */ |
643 | |
644 | static int |
645 | write_rtnbeg (int rtnnum, int dosizeonly) |
646 | { |
647 | const char *rtnname; |
648 | int rtnnamelen; |
649 | char *rtnentryname; |
650 | int totsize = 0; |
651 | char label[MAX_ARTIFICIAL_LABEL_BYTES]; |
652 | DST_ROUTINE_BEGIN rtnbeg; |
653 | DST_PROLOG prolog; |
654 | |
655 | rtnname = funcnam_table[rtnnum]; |
656 | rtnnamelen = strlen (rtnname); |
657 | rtnentryname = concat (rtnname, "..en" , NULL); |
658 | |
659 | if (!strcmp (rtnname, "main" )) |
660 | { |
661 | DST_HEADER header; |
662 | const char *go = "TRANSFER$BREAK$GO" ; |
663 | |
664 | /* This command isn't documented in DSTRECORDS, so it's made to |
665 | look like what DEC C does */ |
666 | |
667 | /* header size - 1st byte + flag byte + STO_LW size |
668 | + string count byte + string length */ |
669 | header.dst__header_length.dst_w_length |
670 | = DST_K_DST_HEADER_SIZE - 1 + 1 + 4 + 1 + strlen (go); |
671 | header.dst__header_type.dst_w_type = DST_K_TBG; |
672 | |
673 | totsize += write_debug_header (&header, "transfer" , dosizeonly); |
674 | |
675 | /* I think this is a flag byte, but I don't know what this flag means */ |
676 | totsize += write_debug_data1 (0x1, "flags ???" , dosizeonly); |
677 | |
678 | /* Routine Begin PD Address */ |
679 | totsize += write_debug_addr (rtnname, "main procedure descriptor" , |
680 | dosizeonly); |
681 | totsize += write_debug_data1 (strlen (go), "length of main_name" , |
682 | dosizeonly); |
683 | totsize += write_debug_string (go, "main name" , dosizeonly); |
684 | } |
685 | |
686 | /* The header length never includes the length byte. */ |
687 | rtnbeg.dst_a_rtnbeg_header.dst__header_length.dst_w_length |
688 | = DST_K_RTNBEG_SIZE + rtnnamelen - 1; |
689 | rtnbeg.dst_a_rtnbeg_header.dst__header_type.dst_w_type = DST_K_RTNBEG; |
690 | rtnbeg.dst_b_rtnbeg_flags.dst_v_rtnbeg_unused = 0; |
691 | rtnbeg.dst_b_rtnbeg_flags.dst_v_rtnbeg_unalloc = 0; |
692 | rtnbeg.dst_b_rtnbeg_flags.dst_v_rtnbeg_prototype = 0; |
693 | rtnbeg.dst_b_rtnbeg_flags.dst_v_rtnbeg_inlined = 0; |
694 | rtnbeg.dst_b_rtnbeg_flags.dst_v_rtnbeg_no_call = 1; |
695 | rtnbeg.dst_b_rtnbeg_name = rtnnamelen; |
696 | |
697 | totsize += write_debug_header (&rtnbeg.dst_a_rtnbeg_header, "rtnbeg" , |
698 | dosizeonly); |
699 | totsize += write_debug_data1 (*((char *) &rtnbeg.dst_b_rtnbeg_flags), |
700 | "flags" , dosizeonly); |
701 | |
702 | /* Routine Begin Address */ |
703 | totsize += write_debug_addr (rtnentryname, "routine entry name" , dosizeonly); |
704 | |
705 | /* Routine Begin PD Address */ |
706 | totsize += write_debug_addr (rtnname, "routine procedure descriptor" , |
707 | dosizeonly); |
708 | |
709 | /* Routine Begin Name */ |
710 | totsize += write_debug_data1 (rtnbeg.dst_b_rtnbeg_name, |
711 | "length of routine name" , dosizeonly); |
712 | |
713 | totsize += write_debug_string (rtnname, "routine name" , dosizeonly); |
714 | |
715 | free (rtnentryname); |
716 | |
717 | if (debug_info_level > DINFO_LEVEL_TERSE) |
718 | { |
719 | prolog.dst_a_prolog_header.dst__header_length.dst_w_length |
720 | = DST_K_PROLOG_SIZE - 1; |
721 | prolog.dst_a_prolog_header.dst__header_type.dst_w_type = DST_K_PROLOG; |
722 | |
723 | totsize += write_debug_header (&prolog.dst_a_prolog_header, "prolog" , |
724 | dosizeonly); |
725 | |
726 | ASM_GENERATE_INTERNAL_LABEL |
727 | (label, FUNC_PROLOG_LABEL, |
728 | funcnum_table[rtnnum]); |
729 | totsize += write_debug_addr (label, "prolog breakpoint addr" , |
730 | dosizeonly); |
731 | } |
732 | |
733 | return totsize; |
734 | } |
735 | |
736 | /* Output a routine end trailer for routine RTNNUM and return the header size. |
737 | Just return the size if DOSIZEONLY is nonzero. */ |
738 | |
739 | static int |
740 | write_rtnend (int rtnnum, int dosizeonly) |
741 | { |
742 | DST_ROUTINE_END rtnend; |
743 | char label1[MAX_ARTIFICIAL_LABEL_BYTES]; |
744 | char label2[MAX_ARTIFICIAL_LABEL_BYTES]; |
745 | int totsize; |
746 | |
747 | totsize = 0; |
748 | |
749 | rtnend.dst_a_rtnend_header.dst__header_length.dst_w_length |
750 | = DST_K_RTNEND_SIZE - 1; |
751 | rtnend.dst_a_rtnend_header.dst__header_type.dst_w_type = DST_K_RTNEND; |
752 | rtnend.dst_b_rtnend_unused = 0; |
753 | rtnend.dst_l_rtnend_size = 0; /* Calculated below. */ |
754 | |
755 | totsize += write_debug_header (&rtnend.dst_a_rtnend_header, "rtnend" , |
756 | dosizeonly); |
757 | totsize += write_debug_data1 (rtnend.dst_b_rtnend_unused, "unused" , |
758 | dosizeonly); |
759 | |
760 | ASM_GENERATE_INTERNAL_LABEL |
761 | (label1, FUNC_BEGIN_LABEL, |
762 | funcnum_table[rtnnum]); |
763 | ASM_GENERATE_INTERNAL_LABEL |
764 | (label2, FUNC_END_LABEL, |
765 | funcnum_table[rtnnum]); |
766 | totsize += write_debug_delta4 (label2, label1, "routine size" , dosizeonly); |
767 | |
768 | return totsize; |
769 | } |
770 | |
771 | #define K_DELTA_PC(I) \ |
772 | ((I) < 128 ? -(I) : (I) < 65536 ? DST_K_DELTA_PC_W : DST_K_DELTA_PC_L) |
773 | |
774 | #define K_SET_LINUM(I) \ |
775 | ((I) < 256 ? DST_K_SET_LINUM_B \ |
776 | : (I) < 65536 ? DST_K_SET_LINUM : DST_K_SET_LINUM_L) |
777 | |
778 | #define K_INCR_LINUM(I) \ |
779 | ((I) < 256 ? DST_K_INCR_LINUM \ |
780 | : (I) < 65536 ? DST_K_INCR_LINUM_W : DST_K_INCR_LINUM_L) |
781 | |
782 | /* Output the PC to line number correlations and return the size. Just return |
783 | the size if DOSIZEONLY is nonzero */ |
784 | |
785 | static int |
786 | write_pclines (int dosizeonly) |
787 | { |
788 | unsigned i; |
789 | int fn; |
790 | int ln, lastln; |
791 | int linestart = 0; |
792 | int max_line; |
793 | DST_LINE_NUM_HEADER line_num; |
794 | DST_PCLINE_COMMANDS pcline; |
795 | char label[MAX_ARTIFICIAL_LABEL_BYTES]; |
796 | char lastlabel[MAX_ARTIFICIAL_LABEL_BYTES]; |
797 | int totsize = 0; |
798 | char buff[256]; |
799 | |
800 | max_line = file_info_table[1].max_line; |
801 | file_info_table[1].listing_line_start = linestart; |
802 | linestart = linestart + ((max_line / 100000) + 1) * 100000; |
803 | |
804 | for (i = 2; i < file_info_table_in_use; i++) |
805 | { |
806 | max_line = file_info_table[i].max_line; |
807 | file_info_table[i].listing_line_start = linestart; |
808 | linestart = linestart + ((max_line / 10000) + 1) * 10000; |
809 | } |
810 | |
811 | /* Set starting address to beginning of text section. */ |
812 | line_num.dst_a_line_num_header.dst__header_length.dst_w_length = 8; |
813 | line_num.dst_a_line_num_header.dst__header_type.dst_w_type = DST_K_LINE_NUM; |
814 | pcline.dst_b_pcline_command = DST_K_SET_ABS_PC; |
815 | |
816 | totsize += write_debug_header (&line_num.dst_a_line_num_header, |
817 | "line_num" , dosizeonly); |
818 | totsize += write_debug_data1 (pcline.dst_b_pcline_command, |
819 | "line_num (SET ABS PC)" , dosizeonly); |
820 | |
821 | if (dosizeonly) |
822 | totsize += 4; |
823 | else |
824 | { |
825 | ASM_OUTPUT_DEBUG_ADDR (asm_out_file, TEXT_SECTION_ASM_OP); |
826 | if (flag_verbose_asm) |
827 | fprintf (asm_out_file, "\t%s line_num" , ASM_COMMENT_START); |
828 | fputc ('\n', asm_out_file); |
829 | } |
830 | |
831 | fn = line_info_table[1].dst_file_num; |
832 | ln = (file_info_table[fn].listing_line_start |
833 | + line_info_table[1].dst_line_num); |
834 | line_num.dst_a_line_num_header.dst__header_length.dst_w_length = 4 + 4; |
835 | pcline.dst_b_pcline_command = DST_K_SET_LINUM_L; |
836 | |
837 | totsize += write_debug_header (&line_num.dst_a_line_num_header, |
838 | "line_num" , dosizeonly); |
839 | totsize += write_debug_data1 (pcline.dst_b_pcline_command, |
840 | "line_num (SET LINUM LONG)" , dosizeonly); |
841 | |
842 | sprintf (buff, "line_num (%d)" , ln ? ln - 1 : 0); |
843 | totsize += write_debug_data4 (ln ? ln - 1 : 0, buff, dosizeonly); |
844 | |
845 | lastln = ln; |
846 | strcpy (lastlabel, TEXT_SECTION_ASM_OP); |
847 | for (i = 1; i < line_info_table_in_use; i++) |
848 | { |
849 | int extrabytes; |
850 | |
851 | fn = line_info_table[i].dst_file_num; |
852 | ln = (file_info_table[fn].listing_line_start |
853 | + line_info_table[i].dst_line_num); |
854 | |
855 | if (ln - lastln > 1) |
856 | extrabytes = 5; /* NUMBYTES (ln - lastln - 1) + 1; */ |
857 | else if (ln <= lastln) |
858 | extrabytes = 5; /* NUMBYTES (ln - 1) + 1; */ |
859 | else |
860 | extrabytes = 0; |
861 | |
862 | line_num.dst_a_line_num_header.dst__header_length.dst_w_length |
863 | = 8 + extrabytes; |
864 | |
865 | totsize += write_debug_header |
866 | (&line_num.dst_a_line_num_header, "line_num" , dosizeonly); |
867 | |
868 | if (ln - lastln > 1) |
869 | { |
870 | int lndif = ln - lastln - 1; |
871 | |
872 | /* K_INCR_LINUM (lndif); */ |
873 | pcline.dst_b_pcline_command = DST_K_INCR_LINUM_L; |
874 | |
875 | totsize += write_debug_data1 (pcline.dst_b_pcline_command, |
876 | "line_num (INCR LINUM LONG)" , |
877 | dosizeonly); |
878 | |
879 | sprintf (buff, "line_num (%d)" , lndif); |
880 | totsize += write_debug_data4 (lndif, buff, dosizeonly); |
881 | } |
882 | else if (ln <= lastln) |
883 | { |
884 | /* K_SET_LINUM (ln-1); */ |
885 | pcline.dst_b_pcline_command = DST_K_SET_LINUM_L; |
886 | |
887 | totsize += write_debug_data1 (pcline.dst_b_pcline_command, |
888 | "line_num (SET LINUM LONG)" , |
889 | dosizeonly); |
890 | |
891 | sprintf (buff, "line_num (%d)" , ln - 1); |
892 | totsize += write_debug_data4 (ln - 1, buff, dosizeonly); |
893 | } |
894 | |
895 | pcline.dst_b_pcline_command = DST_K_DELTA_PC_L; |
896 | |
897 | totsize += write_debug_data1 (pcline.dst_b_pcline_command, |
898 | "line_num (DELTA PC LONG)" , dosizeonly); |
899 | |
900 | ASM_GENERATE_INTERNAL_LABEL (label, LINE_CODE_LABEL, i); |
901 | totsize += write_debug_delta4 (label, lastlabel, "increment line_num" , |
902 | dosizeonly); |
903 | |
904 | lastln = ln; |
905 | strcpy (lastlabel, label); |
906 | } |
907 | |
908 | return totsize; |
909 | } |
910 | |
911 | /* Output a source correlation for file FILEID using information saved in |
912 | FILE_INFO_ENTRY and return the size. Just return the size if DOSIZEONLY is |
913 | nonzero. */ |
914 | |
915 | static int |
916 | write_srccorr (int fileid, dst_file_info_entry file_info_entry, |
917 | int dosizeonly) |
918 | { |
919 | int src_command_size; |
920 | int linesleft = file_info_entry.max_line; |
921 | int linestart = file_info_entry.listing_line_start; |
922 | int flen = strlen (file_info_entry.file_name); |
923 | int linestodo = 0; |
924 | DST_SOURCE_CORR src_header; |
925 | DST_SRC_COMMAND src_command; |
926 | DST_SRC_COMMAND src_command_sf; |
927 | DST_SRC_COMMAND src_command_sl; |
928 | DST_SRC_COMMAND src_command_sr; |
929 | DST_SRC_COMMAND src_command_dl; |
930 | DST_SRC_CMDTRLR src_cmdtrlr; |
931 | char buff[256]; |
932 | int totsize = 0; |
933 | |
934 | if (fileid == 1) |
935 | { |
936 | src_header.dst_a_source_corr_header.dst__header_length.dst_w_length |
937 | = DST_K_SOURCE_CORR_HEADER_SIZE + 1 - 1; |
938 | src_header.dst_a_source_corr_header.dst__header_type.dst_w_type |
939 | = DST_K_SOURCE; |
940 | src_command.dst_b_src_command = DST_K_SRC_FORMFEED; |
941 | |
942 | totsize += write_debug_header (&src_header.dst_a_source_corr_header, |
943 | "source corr" , dosizeonly); |
944 | |
945 | totsize += write_debug_data1 (src_command.dst_b_src_command, |
946 | "source_corr (SRC FORMFEED)" , |
947 | dosizeonly); |
948 | } |
949 | |
950 | src_command_size |
951 | = DST_K_SRC_COMMAND_SIZE + flen + DST_K_SRC_CMDTRLR_SIZE; |
952 | src_command.dst_b_src_command = DST_K_SRC_DECLFILE; |
953 | src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_length |
954 | = src_command_size - 2; |
955 | src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_flags = 0; |
956 | src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_w_src_df_fileid |
957 | = fileid; |
958 | src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_q_src_df_rms_cdt |
959 | = file_info_entry.cdt; |
960 | src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_l_src_df_rms_ebk |
961 | = file_info_entry.ebk; |
962 | src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_w_src_df_rms_ffb |
963 | = file_info_entry.ffb; |
964 | src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_rms_rfo |
965 | = file_info_entry.rfo; |
966 | src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_filename |
967 | = flen; |
968 | |
969 | src_header.dst_a_source_corr_header.dst__header_length.dst_w_length |
970 | = DST_K_SOURCE_CORR_HEADER_SIZE + src_command_size - 1; |
971 | src_header.dst_a_source_corr_header.dst__header_type.dst_w_type |
972 | = DST_K_SOURCE; |
973 | |
974 | src_cmdtrlr.dst_b_src_df_libmodname = 0; |
975 | |
976 | totsize += write_debug_header (&src_header.dst_a_source_corr_header, |
977 | "source corr" , dosizeonly); |
978 | totsize += write_debug_data1 (src_command.dst_b_src_command, |
979 | "source_corr (DECL SRC FILE)" , dosizeonly); |
980 | totsize += write_debug_data1 |
981 | (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_length, |
982 | "source_corr (length)" , dosizeonly); |
983 | |
984 | totsize += write_debug_data1 |
985 | (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_flags, |
986 | "source_corr (flags)" , dosizeonly); |
987 | |
988 | totsize += write_debug_data2 |
989 | (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_w_src_df_fileid, |
990 | "source_corr (fileid)" , dosizeonly); |
991 | |
992 | totsize += write_debug_data8 |
993 | (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_q_src_df_rms_cdt, |
994 | "source_corr (creation date)" , dosizeonly); |
995 | |
996 | totsize += write_debug_data4 |
997 | (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_l_src_df_rms_ebk, |
998 | "source_corr (EOF block number)" , dosizeonly); |
999 | |
1000 | totsize += write_debug_data2 |
1001 | (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_w_src_df_rms_ffb, |
1002 | "source_corr (first free byte)" , dosizeonly); |
1003 | |
1004 | totsize += write_debug_data1 |
1005 | (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_rms_rfo, |
1006 | "source_corr (record and file organization)" , dosizeonly); |
1007 | |
1008 | totsize += write_debug_data1 |
1009 | (src_command.dst_a_src_cmd_fields.dst_a_src_decl_src.dst_b_src_df_filename, |
1010 | "source_corr (filename length)" , dosizeonly); |
1011 | |
1012 | totsize += write_debug_string (remap_debug_filename ( |
1013 | file_info_entry.file_name), |
1014 | "source file name" , dosizeonly); |
1015 | totsize += write_debug_data1 (src_cmdtrlr.dst_b_src_df_libmodname, |
1016 | "source_corr (libmodname)" , dosizeonly); |
1017 | |
1018 | src_command_sf.dst_b_src_command = DST_K_SRC_SETFILE; |
1019 | src_command_sf.dst_a_src_cmd_fields.dst_w_src_unsword = fileid; |
1020 | |
1021 | src_command_sr.dst_b_src_command = DST_K_SRC_SETREC_W; |
1022 | src_command_sr.dst_a_src_cmd_fields.dst_w_src_unsword = 1; |
1023 | |
1024 | src_command_sl.dst_b_src_command = DST_K_SRC_SETLNUM_L; |
1025 | src_command_sl.dst_a_src_cmd_fields.dst_l_src_unslong = linestart + 1; |
1026 | |
1027 | src_command_dl.dst_b_src_command = DST_K_SRC_DEFLINES_W; |
1028 | |
1029 | if (linesleft > 65534) |
1030 | linesleft = linesleft - 65534, linestodo = 65534; |
1031 | else |
1032 | linestodo = linesleft, linesleft = 0; |
1033 | |
1034 | src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword = linestodo; |
1035 | |
1036 | src_header.dst_a_source_corr_header.dst__header_length.dst_w_length |
1037 | = DST_K_SOURCE_CORR_HEADER_SIZE + 3 + 3 + 5 + 3 - 1; |
1038 | src_header.dst_a_source_corr_header.dst__header_type.dst_w_type |
1039 | = DST_K_SOURCE; |
1040 | |
1041 | if (src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword) |
1042 | { |
1043 | totsize += write_debug_header (&src_header.dst_a_source_corr_header, |
1044 | "source corr" , dosizeonly); |
1045 | |
1046 | totsize += write_debug_data1 (src_command_sf.dst_b_src_command, |
1047 | "source_corr (src setfile)" , dosizeonly); |
1048 | |
1049 | totsize += write_debug_data2 |
1050 | (src_command_sf.dst_a_src_cmd_fields.dst_w_src_unsword, |
1051 | "source_corr (fileid)" , dosizeonly); |
1052 | |
1053 | totsize += write_debug_data1 (src_command_sr.dst_b_src_command, |
1054 | "source_corr (setrec)" , dosizeonly); |
1055 | |
1056 | totsize += write_debug_data2 |
1057 | (src_command_sr.dst_a_src_cmd_fields.dst_w_src_unsword, |
1058 | "source_corr (recnum)" , dosizeonly); |
1059 | |
1060 | totsize += write_debug_data1 (src_command_sl.dst_b_src_command, |
1061 | "source_corr (setlnum)" , dosizeonly); |
1062 | |
1063 | totsize += write_debug_data4 |
1064 | (src_command_sl.dst_a_src_cmd_fields.dst_l_src_unslong, |
1065 | "source_corr (linenum)" , dosizeonly); |
1066 | |
1067 | totsize += write_debug_data1 (src_command_dl.dst_b_src_command, |
1068 | "source_corr (deflines)" , dosizeonly); |
1069 | |
1070 | sprintf (buff, "source_corr (%d)" , |
1071 | src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword); |
1072 | totsize += write_debug_data2 |
1073 | (src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword, |
1074 | buff, dosizeonly); |
1075 | |
1076 | while (linesleft > 0) |
1077 | { |
1078 | src_header.dst_a_source_corr_header.dst__header_length.dst_w_length |
1079 | = DST_K_SOURCE_CORR_HEADER_SIZE + 3 - 1; |
1080 | src_header.dst_a_source_corr_header.dst__header_type.dst_w_type |
1081 | = DST_K_SOURCE; |
1082 | src_command_dl.dst_b_src_command = DST_K_SRC_DEFLINES_W; |
1083 | |
1084 | if (linesleft > 65534) |
1085 | linesleft = linesleft - 65534, linestodo = 65534; |
1086 | else |
1087 | linestodo = linesleft, linesleft = 0; |
1088 | |
1089 | src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword = linestodo; |
1090 | |
1091 | totsize += write_debug_header (&src_header.dst_a_source_corr_header, |
1092 | "source corr" , dosizeonly); |
1093 | totsize += write_debug_data1 (src_command_dl.dst_b_src_command, |
1094 | "source_corr (deflines)" , dosizeonly); |
1095 | sprintf (buff, "source_corr (%d)" , |
1096 | src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword); |
1097 | totsize += write_debug_data2 |
1098 | (src_command_dl.dst_a_src_cmd_fields.dst_w_src_unsword, |
1099 | buff, dosizeonly); |
1100 | } |
1101 | } |
1102 | |
1103 | return totsize; |
1104 | } |
1105 | |
1106 | /* Output all the source correlation entries and return the size. Just return |
1107 | the size if DOSIZEONLY is nonzero. */ |
1108 | |
1109 | static int |
1110 | write_srccorrs (int dosizeonly) |
1111 | { |
1112 | unsigned int i; |
1113 | int totsize = 0; |
1114 | |
1115 | for (i = 1; i < file_info_table_in_use; i++) |
1116 | totsize += write_srccorr (i, file_info_table[i], dosizeonly); |
1117 | |
1118 | return totsize; |
1119 | } |
1120 | |
1121 | /* Output a marker (i.e. a label) for the beginning of a function, before |
1122 | the prologue. */ |
1123 | |
1124 | static void |
1125 | vmsdbgout_begin_prologue (unsigned int line, unsigned int column, |
1126 | const char *file) |
1127 | { |
1128 | char label[MAX_ARTIFICIAL_LABEL_BYTES]; |
1129 | |
1130 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1131 | (*dwarf2_debug_hooks.begin_prologue) (line, column, file); |
1132 | |
1133 | if (debug_info_level > DINFO_LEVEL_NONE) |
1134 | { |
1135 | ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL, |
1136 | current_function_funcdef_no); |
1137 | ASM_OUTPUT_LABEL (asm_out_file, label); |
1138 | } |
1139 | } |
1140 | |
1141 | /* Output a marker (i.e. a label) for the beginning of a function, after |
1142 | the prologue. */ |
1143 | |
1144 | static void |
1145 | vmsdbgout_end_prologue (unsigned int line, const char *file) |
1146 | { |
1147 | char label[MAX_ARTIFICIAL_LABEL_BYTES]; |
1148 | |
1149 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1150 | (*dwarf2_debug_hooks.end_prologue) (line, file); |
1151 | |
1152 | if (debug_info_level > DINFO_LEVEL_TERSE) |
1153 | { |
1154 | ASM_GENERATE_INTERNAL_LABEL (label, FUNC_PROLOG_LABEL, |
1155 | current_function_funcdef_no); |
1156 | ASM_OUTPUT_LABEL (asm_out_file, label); |
1157 | |
1158 | /* VMS PCA expects every PC range to correlate to some line and file. */ |
1159 | vmsdbgout_write_source_line (line, file, 0, true); |
1160 | } |
1161 | } |
1162 | |
1163 | /* No output for VMS debug, but make obligatory call to Dwarf2 debug */ |
1164 | |
1165 | static void |
1166 | vmsdbgout_end_function (unsigned int line) |
1167 | { |
1168 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1169 | (*dwarf2_debug_hooks.end_function) (line); |
1170 | } |
1171 | |
1172 | /* Output a marker (i.e. a label) for the beginning of the epilogue. |
1173 | This gets called *before* the epilogue code has been generated. */ |
1174 | |
1175 | static void |
1176 | vmsdbgout_begin_epilogue (unsigned int line, const char *file) |
1177 | { |
1178 | char label[MAX_ARTIFICIAL_LABEL_BYTES]; |
1179 | static int save_current_function_funcdef_no = -1; |
1180 | |
1181 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1182 | (*dwarf2_debug_hooks.begin_epilogue) (line, file); |
1183 | |
1184 | if (debug_info_level > DINFO_LEVEL_NONE) |
1185 | { |
1186 | if (save_current_function_funcdef_no != current_function_funcdef_no) |
1187 | { |
1188 | /* Output a label to mark the endpoint of the code generated for this |
1189 | function. */ |
1190 | ASM_GENERATE_INTERNAL_LABEL (label, FUNC_EPILOG_LABEL, |
1191 | current_function_funcdef_no); |
1192 | |
1193 | ASM_OUTPUT_LABEL (asm_out_file, label); |
1194 | |
1195 | save_current_function_funcdef_no = current_function_funcdef_no; |
1196 | |
1197 | /* VMS PCA expects every PC range to correlate to some line and |
1198 | file. */ |
1199 | vmsdbgout_write_source_line (line, file, 0, true); |
1200 | } |
1201 | } |
1202 | } |
1203 | |
1204 | /* Output a marker (i.e. a label) for the absolute end of the generated code |
1205 | for a function definition. This gets called *after* the epilogue code has |
1206 | been generated. */ |
1207 | |
1208 | static void |
1209 | vmsdbgout_end_epilogue (unsigned int line, const char *file) |
1210 | { |
1211 | char label[MAX_ARTIFICIAL_LABEL_BYTES]; |
1212 | |
1213 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1214 | (*dwarf2_debug_hooks.end_epilogue) (line, file); |
1215 | |
1216 | if (debug_info_level > DINFO_LEVEL_NONE) |
1217 | { |
1218 | /* Output a label to mark the endpoint of the code generated for this |
1219 | function. */ |
1220 | ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, |
1221 | current_function_funcdef_no); |
1222 | ASM_OUTPUT_LABEL (asm_out_file, label); |
1223 | |
1224 | /* VMS PCA expects every PC range to correlate to some line and file. */ |
1225 | vmsdbgout_write_source_line (line, file, 0, true); |
1226 | } |
1227 | } |
1228 | |
1229 | /* Output a marker (i.e. a label) for the beginning of the generated code for |
1230 | a lexical block. */ |
1231 | |
1232 | static void |
1233 | vmsdbgout_begin_block (unsigned line, unsigned blocknum) |
1234 | { |
1235 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1236 | (*dwarf2_debug_hooks.begin_block) (line, blocknum); |
1237 | |
1238 | if (debug_info_level > DINFO_LEVEL_TERSE) |
1239 | targetm.asm_out.internal_label (asm_out_file, BLOCK_BEGIN_LABEL, blocknum); |
1240 | } |
1241 | |
1242 | /* Output a marker (i.e. a label) for the end of the generated code for a |
1243 | lexical block. */ |
1244 | |
1245 | static void |
1246 | vmsdbgout_end_block (unsigned line, unsigned blocknum) |
1247 | { |
1248 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1249 | (*dwarf2_debug_hooks.end_block) (line, blocknum); |
1250 | |
1251 | if (debug_info_level > DINFO_LEVEL_TERSE) |
1252 | targetm.asm_out.internal_label (asm_out_file, BLOCK_END_LABEL, blocknum); |
1253 | } |
1254 | |
1255 | /* Not implemented in VMS Debug. */ |
1256 | |
1257 | static bool |
1258 | vmsdbgout_ignore_block (const_tree block) |
1259 | { |
1260 | bool retval = 0; |
1261 | |
1262 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1263 | retval = (*dwarf2_debug_hooks.ignore_block) (block); |
1264 | |
1265 | return retval; |
1266 | } |
1267 | |
1268 | /* Add an entry for function DECL into the funcnam_table. */ |
1269 | |
1270 | static void |
1271 | vmsdbgout_begin_function (tree decl) |
1272 | { |
1273 | const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0); |
1274 | |
1275 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1276 | (*dwarf2_debug_hooks.begin_function) (decl); |
1277 | |
1278 | /* Add the new entry to the end of the function name table. */ |
1279 | funcnam_table.safe_push (xstrdup (name)); |
1280 | funcnum_table.safe_push (current_function_funcdef_no); |
1281 | } |
1282 | |
1283 | static char fullname_buff [4096]; |
1284 | |
1285 | /* Return the full file specification for FILENAME. The specification must be |
1286 | in VMS syntax in order to be processed by VMS Debug. */ |
1287 | |
1288 | static char * |
1289 | full_name (const char *filename) |
1290 | { |
1291 | #ifdef VMS |
1292 | FILE *fp = fopen (filename, "r" ); |
1293 | |
1294 | fgetname (fp, fullname_buff, 1); |
1295 | fclose (fp); |
1296 | #else |
1297 | /* Unix paths really mess up VMS debug. Better to just output the |
1298 | base filename. */ |
1299 | strcpy (fullname_buff, filename); |
1300 | #endif |
1301 | |
1302 | return fullname_buff; |
1303 | } |
1304 | |
1305 | /* Lookup a filename (in the list of filenames that we know about here in |
1306 | vmsdbgout.cc) and return its "index". The index of each (known) filename is |
1307 | just a unique number which is associated with only that one filename. We |
1308 | need such numbers for the sake of generating labels and references |
1309 | to those files numbers. If the filename given as an argument is not |
1310 | found in our current list, add it to the list and assign it the next |
1311 | available unique index number. In order to speed up searches, we remember |
1312 | the index of the filename was looked up last. This handles the majority of |
1313 | all searches. */ |
1314 | |
1315 | static unsigned int |
1316 | lookup_filename (const char *file_name) |
1317 | { |
1318 | static unsigned int last_file_lookup_index = 0; |
1319 | char *fn; |
1320 | unsigned i; |
1321 | const char *fnam; |
1322 | long long cdt = 0; |
1323 | long ebk = 0; |
1324 | short ffb = 0; |
1325 | char rfo = 0; |
1326 | long siz = 0; |
1327 | int ver = 0; |
1328 | |
1329 | fnam = full_name (file_name); |
1330 | |
1331 | /* Check to see if the file name that was searched on the previous call |
1332 | matches this file name. If so, return the index. */ |
1333 | if (last_file_lookup_index != 0) |
1334 | { |
1335 | fn = file_info_table[last_file_lookup_index].file_name; |
1336 | if (strcmp (fnam, fn) == 0) |
1337 | return last_file_lookup_index; |
1338 | } |
1339 | |
1340 | /* Didn't match the previous lookup, search the table */ |
1341 | for (i = 1; i < file_info_table_in_use; ++i) |
1342 | { |
1343 | fn = file_info_table[i].file_name; |
1344 | if (strcmp (fnam, fn) == 0) |
1345 | { |
1346 | last_file_lookup_index = i; |
1347 | return i; |
1348 | } |
1349 | } |
1350 | |
1351 | /* Prepare to add a new table entry by making sure there is enough space in |
1352 | the table to do so. If not, expand the current table. */ |
1353 | if (file_info_table_in_use == file_info_table_allocated) |
1354 | { |
1355 | |
1356 | file_info_table_allocated += FILE_TABLE_INCREMENT; |
1357 | file_info_table = XRESIZEVEC (dst_file_info_entry, file_info_table, |
1358 | file_info_table_allocated); |
1359 | } |
1360 | |
1361 | if (vms_file_stats_name (file_name, &cdt, &siz, &rfo, &ver) == 0) |
1362 | { |
1363 | ebk = siz / 512 + 1; |
1364 | ffb = siz - ((siz / 512) * 512); |
1365 | } |
1366 | |
1367 | /* Add the new entry to the end of the filename table. */ |
1368 | file_info_table[file_info_table_in_use].file_name = xstrdup (fnam); |
1369 | file_info_table[file_info_table_in_use].max_line = 0; |
1370 | file_info_table[file_info_table_in_use].cdt = cdt; |
1371 | file_info_table[file_info_table_in_use].ebk = ebk; |
1372 | file_info_table[file_info_table_in_use].ffb = ffb; |
1373 | file_info_table[file_info_table_in_use].rfo = rfo; |
1374 | |
1375 | last_file_lookup_index = file_info_table_in_use++; |
1376 | return last_file_lookup_index; |
1377 | } |
1378 | |
1379 | /* Output a label to mark the beginning of a source code line entry |
1380 | and record information relating to this source line, in |
1381 | 'line_info_table' for later output of the .debug_line section. */ |
1382 | |
1383 | static void |
1384 | vmsdbgout_write_source_line (unsigned line, const char *filename, |
1385 | int /* discriminator */, bool /* is_stmt */) |
1386 | { |
1387 | dst_line_info_ref line_info; |
1388 | |
1389 | targetm.asm_out.internal_label (asm_out_file, LINE_CODE_LABEL, |
1390 | line_info_table_in_use); |
1391 | |
1392 | /* Expand the line info table if necessary. */ |
1393 | if (line_info_table_in_use == line_info_table_allocated) |
1394 | { |
1395 | line_info_table_allocated += LINE_INFO_TABLE_INCREMENT; |
1396 | line_info_table = XRESIZEVEC (dst_line_info_entry, line_info_table, |
1397 | line_info_table_allocated); |
1398 | } |
1399 | |
1400 | /* Add the new entry at the end of the line_info_table. */ |
1401 | line_info = &line_info_table[line_info_table_in_use++]; |
1402 | line_info->dst_file_num = lookup_filename (filename); |
1403 | line_info->dst_line_num = line; |
1404 | if (line > file_info_table[line_info->dst_file_num].max_line) |
1405 | file_info_table[line_info->dst_file_num].max_line = line; |
1406 | } |
1407 | |
1408 | static void |
1409 | vmsdbgout_source_line (unsigned line, unsigned int column, |
1410 | const char *filename, |
1411 | int discriminator, bool is_stmt) |
1412 | { |
1413 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1414 | (*dwarf2_debug_hooks.source_line) (line, column, filename, discriminator, |
1415 | is_stmt); |
1416 | |
1417 | if (debug_info_level >= DINFO_LEVEL_TERSE) |
1418 | vmsdbgout_write_source_line (line, filename, discriminator, is_stmt); |
1419 | } |
1420 | |
1421 | /* Record the beginning of a new source file, for later output. |
1422 | At present, unimplemented. */ |
1423 | |
1424 | static void |
1425 | vmsdbgout_start_source_file (unsigned int lineno, const char *filename) |
1426 | { |
1427 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1428 | (*dwarf2_debug_hooks.start_source_file) (lineno, filename); |
1429 | } |
1430 | |
1431 | /* Record the end of a source file, for later output. |
1432 | At present, unimplemented. */ |
1433 | |
1434 | static void |
1435 | vmsdbgout_end_source_file (unsigned int lineno ATTRIBUTE_UNUSED) |
1436 | { |
1437 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1438 | (*dwarf2_debug_hooks.end_source_file) (lineno); |
1439 | } |
1440 | |
1441 | /* Set up for Debug output at the start of compilation. */ |
1442 | |
1443 | static void |
1444 | vmsdbgout_init (const char *filename) |
1445 | { |
1446 | const char *language_string = lang_hooks.name; |
1447 | |
1448 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1449 | (*dwarf2_debug_hooks.init) (filename); |
1450 | |
1451 | if (debug_info_level == DINFO_LEVEL_NONE) |
1452 | return; |
1453 | |
1454 | /* Remember the name of the primary input file. */ |
1455 | primary_filename = filename; |
1456 | |
1457 | /* Allocate the initial hunk of the file_info_table. */ |
1458 | file_info_table = XCNEWVEC (dst_file_info_entry, FILE_TABLE_INCREMENT); |
1459 | file_info_table_allocated = FILE_TABLE_INCREMENT; |
1460 | /* Skip the first entry - file numbers begin at 1. */ |
1461 | file_info_table_in_use = 1; |
1462 | |
1463 | funcnam_table.create (FUNC_TABLE_INITIAL); |
1464 | funcnum_table.create (FUNC_TABLE_INITIAL); |
1465 | |
1466 | /* Allocate the initial hunk of the line_info_table. */ |
1467 | line_info_table = XCNEWVEC (dst_line_info_entry, LINE_INFO_TABLE_INCREMENT); |
1468 | line_info_table_allocated = LINE_INFO_TABLE_INCREMENT; |
1469 | /* zero-th entry is allocated, but unused */ |
1470 | line_info_table_in_use = 1; |
1471 | |
1472 | lookup_filename (primary_filename); |
1473 | |
1474 | if (lang_GNU_C ()) |
1475 | module_language = DST_K_C; |
1476 | else if (lang_GNU_CXX ()) |
1477 | module_language = DST_K_CXX; |
1478 | else if (!strcmp (language_string, "GNU Ada" )) |
1479 | module_language = DST_K_ADA; |
1480 | else if (!strcmp (language_string, "GNU F77" )) |
1481 | module_language = DST_K_FORTRAN; |
1482 | else |
1483 | module_language = DST_K_UNKNOWN; |
1484 | |
1485 | module_producer = concat (language_string, " " , version_string, NULL); |
1486 | |
1487 | ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0); |
1488 | |
1489 | } |
1490 | |
1491 | /* Not implemented in VMS Debug. */ |
1492 | |
1493 | static void |
1494 | vmsdbgout_assembly_start (void) |
1495 | { |
1496 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1497 | (*dwarf2_debug_hooks.assembly_start) (); |
1498 | } |
1499 | |
1500 | /* Not implemented in VMS Debug. */ |
1501 | |
1502 | static void |
1503 | vmsdbgout_define (unsigned int lineno, const char *buffer) |
1504 | { |
1505 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1506 | (*dwarf2_debug_hooks.define) (lineno, buffer); |
1507 | } |
1508 | |
1509 | /* Not implemented in VMS Debug. */ |
1510 | |
1511 | static void |
1512 | vmsdbgout_undef (unsigned int lineno, const char *buffer) |
1513 | { |
1514 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1515 | (*dwarf2_debug_hooks.undef) (lineno, buffer); |
1516 | } |
1517 | |
1518 | /* Not implemented in VMS Debug. */ |
1519 | |
1520 | static void |
1521 | vmsdbgout_function_decl (tree decl) |
1522 | { |
1523 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1524 | (*dwarf2_debug_hooks.function_decl) (decl); |
1525 | } |
1526 | |
1527 | /* Not implemented in VMS Debug. */ |
1528 | |
1529 | static void |
1530 | vmsdbgout_early_global_decl (tree decl) |
1531 | { |
1532 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1533 | (*dwarf2_debug_hooks.early_global_decl) (decl); |
1534 | } |
1535 | |
1536 | /* Not implemented in VMS Debug. */ |
1537 | |
1538 | static void |
1539 | vmsdbgout_late_global_decl (tree decl) |
1540 | { |
1541 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1542 | (*dwarf2_debug_hooks.late_global_decl) (decl); |
1543 | } |
1544 | |
1545 | /* Not implemented in VMS Debug. */ |
1546 | |
1547 | static void |
1548 | vmsdbgout_type_decl (tree decl, int local) |
1549 | { |
1550 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1551 | (*dwarf2_debug_hooks.type_decl) (decl, local); |
1552 | } |
1553 | |
1554 | /* Not implemented in VMS Debug. */ |
1555 | |
1556 | static void |
1557 | vmsdbgout_abstract_function (tree decl) |
1558 | { |
1559 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1560 | (*dwarf2_debug_hooks.outlining_inline_function) (decl); |
1561 | } |
1562 | |
1563 | static void |
1564 | vmsdbgout_early_finish (const char *filename) |
1565 | { |
1566 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1567 | (*dwarf2_debug_hooks.early_finish) (filename); |
1568 | } |
1569 | |
1570 | /* Output stuff that Debug requires at the end of every file and generate the |
1571 | VMS Debug debugging info. */ |
1572 | |
1573 | static void |
1574 | vmsdbgout_finish (const char *filename ATTRIBUTE_UNUSED) |
1575 | { |
1576 | unsigned int i, ifunc; |
1577 | int totsize; |
1578 | |
1579 | if (write_symbols == VMS_AND_DWARF2_DEBUG) |
1580 | (*dwarf2_debug_hooks.finish) (filename); |
1581 | |
1582 | if (debug_info_level == DINFO_LEVEL_NONE) |
1583 | return; |
1584 | |
1585 | /* Output a terminator label for the .text section. */ |
1586 | switch_to_section (text_section); |
1587 | targetm.asm_out.internal_label (asm_out_file, TEXT_END_LABEL, 0); |
1588 | |
1589 | /* Output debugging information. |
1590 | Warning! Do not change the name of the .vmsdebug section without |
1591 | changing it in the assembler also. */ |
1592 | switch_to_section (get_named_section (NULL, ".vmsdebug" , 0)); |
1593 | ASM_OUTPUT_ALIGN (asm_out_file, 0); |
1594 | |
1595 | totsize = write_modbeg (1); |
1596 | FOR_EACH_VEC_ELT (funcnum_table, i, ifunc) |
1597 | { |
1598 | totsize += write_rtnbeg (i, 1); |
1599 | totsize += write_rtnend (i, 1); |
1600 | } |
1601 | totsize += write_pclines (1); |
1602 | |
1603 | write_modbeg (0); |
1604 | FOR_EACH_VEC_ELT (funcnum_table, i, ifunc) |
1605 | { |
1606 | write_rtnbeg (i, 0); |
1607 | write_rtnend (i, 0); |
1608 | } |
1609 | write_pclines (0); |
1610 | |
1611 | if (debug_info_level > DINFO_LEVEL_TERSE) |
1612 | { |
1613 | totsize = write_srccorrs (1); |
1614 | write_srccorrs (0); |
1615 | } |
1616 | |
1617 | totsize = write_modend (1); |
1618 | write_modend (0); |
1619 | } |
1620 | |
1621 | /* Need for both Dwarf2 on IVMS and VMS Debug on AVMS */ |
1622 | |
1623 | #ifdef VMS |
1624 | #define __NEW_STARLET 1 |
1625 | #include <vms/rms.h> |
1626 | #include <vms/atrdef.h> |
1627 | #include <vms/fibdef.h> |
1628 | #include <vms/stsdef.h> |
1629 | #include <vms/iodef.h> |
1630 | #include <vms/fatdef.h> |
1631 | #include <vms/descrip.h> |
1632 | #include <unixlib.h> |
1633 | |
1634 | #define MAXPATH 256 |
1635 | |
1636 | /* descrip.h doesn't have everything ... */ |
1637 | typedef struct fibdef* __fibdef_ptr32 __attribute__ (( mode (SI) )); |
1638 | struct dsc$descriptor_fib |
1639 | { |
1640 | unsigned int fib$l_len; |
1641 | __fibdef_ptr32 fib$l_addr; |
1642 | }; |
1643 | |
1644 | /* I/O Status Block. */ |
1645 | struct IOSB |
1646 | { |
1647 | unsigned short status, count; |
1648 | unsigned int devdep; |
1649 | }; |
1650 | |
1651 | static char *tryfile; |
1652 | |
1653 | /* Variable length string. */ |
1654 | struct vstring |
1655 | { |
1656 | short length; |
1657 | char string[NAM$C_MAXRSS+1]; |
1658 | }; |
1659 | |
1660 | static char filename_buff [MAXPATH]; |
1661 | static char vms_filespec [MAXPATH]; |
1662 | |
1663 | /* Callback function for filespec style conversion. */ |
1664 | |
1665 | static int |
1666 | translate_unix (char *name, int type ATTRIBUTE_UNUSED) |
1667 | { |
1668 | strncpy (filename_buff, name, MAXPATH); |
1669 | filename_buff [MAXPATH - 1] = (char) 0; |
1670 | return 0; |
1671 | } |
1672 | |
1673 | /* Wrapper for DECC function that converts a Unix filespec |
1674 | to VMS style filespec. */ |
1675 | |
1676 | static char * |
1677 | to_vms_file_spec (char *filespec) |
1678 | { |
1679 | strncpy (vms_filespec, "" , MAXPATH); |
1680 | decc$to_vms (filespec, translate_unix, 1, 1); |
1681 | strncpy (vms_filespec, filename_buff, MAXPATH); |
1682 | |
1683 | vms_filespec [MAXPATH - 1] = (char) 0; |
1684 | |
1685 | return vms_filespec; |
1686 | } |
1687 | |
1688 | #else |
1689 | #define VMS_EPOCH_OFFSET 35067168000000000LL |
1690 | #define VMS_GRANULARITY_FACTOR 10000000 |
1691 | #endif |
1692 | |
1693 | /* Return VMS file date, size, format, version given a name. */ |
1694 | |
1695 | int |
1696 | vms_file_stats_name (const char *filename, long long *cdt, long *siz, char *rfo, |
1697 | int *ver) |
1698 | { |
1699 | #ifdef VMS |
1700 | struct FAB fab; |
1701 | struct NAM nam; |
1702 | |
1703 | unsigned long long create; |
1704 | FAT recattr; |
1705 | char ascnamebuff [256]; |
1706 | |
1707 | ATRDEF atrlst[] |
1708 | = { |
1709 | { ATR$S_CREDATE, ATR$C_CREDATE, &create }, |
1710 | { ATR$S_RECATTR, ATR$C_RECATTR, &recattr }, |
1711 | { ATR$S_ASCNAME, ATR$C_ASCNAME, &ascnamebuff }, |
1712 | { 0, 0, 0} |
1713 | }; |
1714 | |
1715 | FIBDEF fib; |
1716 | struct dsc$descriptor_fib fibdsc = {sizeof (fib), (void *) &fib}; |
1717 | |
1718 | struct IOSB iosb; |
1719 | |
1720 | long status; |
1721 | unsigned short chan; |
1722 | |
1723 | struct vstring file; |
1724 | struct dsc$descriptor_s filedsc |
1725 | = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) file.string}; |
1726 | struct vstring device; |
1727 | struct dsc$descriptor_s devicedsc |
1728 | = {NAM$C_MAXRSS, DSC$K_DTYPE_T, DSC$K_CLASS_S, (void *) device.string}; |
1729 | struct vstring result; |
1730 | struct dsc$descriptor_s resultdsc |
1731 | = {NAM$C_MAXRSS, DSC$K_DTYPE_VT, DSC$K_CLASS_VS, (void *) result.string}; |
1732 | |
1733 | if (strcmp (filename, "<internal>" ) == 0 |
1734 | || strcmp (filename, "<built-in>" ) == 0) |
1735 | { |
1736 | if (cdt) |
1737 | *cdt = 0; |
1738 | |
1739 | if (siz) |
1740 | *siz = 0; |
1741 | |
1742 | if (rfo) |
1743 | *rfo = 0; |
1744 | |
1745 | if (ver) |
1746 | *ver = 0; |
1747 | |
1748 | return 0; |
1749 | } |
1750 | |
1751 | tryfile = to_vms_file_spec (filename); |
1752 | |
1753 | /* Allocate and initialize a FAB and NAM structures. */ |
1754 | fab = cc$rms_fab; |
1755 | nam = cc$rms_nam; |
1756 | |
1757 | nam.nam$l_esa = file.string; |
1758 | nam.nam$b_ess = NAM$C_MAXRSS; |
1759 | nam.nam$l_rsa = result.string; |
1760 | nam.nam$b_rss = NAM$C_MAXRSS; |
1761 | fab.fab$l_fna = tryfile; |
1762 | fab.fab$b_fns = strlen (tryfile); |
1763 | fab.fab$l_nam = &nam; |
1764 | |
1765 | /* Validate filespec syntax and device existence. */ |
1766 | status = SYS$PARSE (&fab, 0, 0); |
1767 | if ((status & 1) != 1) |
1768 | return 1; |
1769 | |
1770 | file.string[nam.nam$b_esl] = 0; |
1771 | |
1772 | /* Find matching filespec. */ |
1773 | status = SYS$SEARCH (&fab, 0, 0); |
1774 | if ((status & 1) != 1) |
1775 | return 1; |
1776 | |
1777 | file.string[nam.nam$b_esl] = 0; |
1778 | result.string[result.length=nam.nam$b_rsl] = 0; |
1779 | |
1780 | /* Get the device name and assign an IO channel. */ |
1781 | strncpy (device.string, nam.nam$l_dev, nam.nam$b_dev); |
1782 | devicedsc.dsc$w_length = nam.nam$b_dev; |
1783 | chan = 0; |
1784 | status = SYS$ASSIGN (&devicedsc, &chan, 0, 0, 0); |
1785 | if ((status & 1) != 1) |
1786 | return 1; |
1787 | |
1788 | /* Initialize the FIB and fill in the directory id field. */ |
1789 | memset (&fib, 0, sizeof (fib)); |
1790 | fib.fib$w_did[0] = nam.nam$w_did[0]; |
1791 | fib.fib$w_did[1] = nam.nam$w_did[1]; |
1792 | fib.fib$w_did[2] = nam.nam$w_did[2]; |
1793 | fib.fib$l_acctl = 0; |
1794 | fib.fib$l_wcc = 0; |
1795 | strcpy (file.string, (strrchr (result.string, ']') + 1)); |
1796 | filedsc.dsc$w_length = strlen (file.string); |
1797 | result.string[result.length = 0] = 0; |
1798 | |
1799 | /* Open and close the file to fill in the attributes. */ |
1800 | status |
1801 | = SYS$QIOW (0, chan, IO$_ACCESS|IO$M_ACCESS, &iosb, 0, 0, |
1802 | &fibdsc, &filedsc, &result.length, &resultdsc, &atrlst, 0); |
1803 | if ((status & 1) != 1) |
1804 | return 1; |
1805 | if ((iosb.status & 1) != 1) |
1806 | return 1; |
1807 | |
1808 | result.string[result.length] = 0; |
1809 | status = SYS$QIOW (0, chan, IO$_DEACCESS, &iosb, 0, 0, &fibdsc, 0, 0, 0, |
1810 | &atrlst, 0); |
1811 | if ((status & 1) != 1) |
1812 | return 1; |
1813 | if ((iosb.status & 1) != 1) |
1814 | return 1; |
1815 | |
1816 | /* Deassign the channel and exit. */ |
1817 | status = SYS$DASSGN (chan); |
1818 | if ((status & 1) != 1) |
1819 | return 1; |
1820 | |
1821 | if (cdt) *cdt = create; |
1822 | if (siz) *siz = (512 * 65536 * recattr.fat$w_efblkh) + |
1823 | (512 * (recattr.fat$w_efblkl - 1)) + |
1824 | recattr.fat$w_ffbyte; |
1825 | if (rfo) *rfo = recattr.fat$v_rtype; |
1826 | if (ver) *ver = strtol (strrchr (ascnamebuff, ';')+1, 0, 10); |
1827 | |
1828 | return 0; |
1829 | #else |
1830 | struct stat buff; |
1831 | |
1832 | if ((stat (filename, &buff)) != 0) |
1833 | return 1; |
1834 | |
1835 | if (cdt) |
1836 | *cdt = (long long) (buff.st_mtime * VMS_GRANULARITY_FACTOR) |
1837 | + VMS_EPOCH_OFFSET; |
1838 | |
1839 | if (siz) |
1840 | *siz = buff.st_size; |
1841 | |
1842 | if (rfo) |
1843 | *rfo = 2; /* Stream LF format */ |
1844 | |
1845 | if (ver) |
1846 | *ver = 1; |
1847 | |
1848 | return 0; |
1849 | #endif |
1850 | } |
1851 | #endif |
1852 | |