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