1 /* codeview.c - CodeView debug support
2 Copyright (C) 2022-2024 Free Software Foundation, Inc.
4 This file is part of GAS, the GNU Assembler.
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 GAS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GAS; see the file COPYING. If not, write to the Free
18 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
24 #include "filenames.h"
27 #if defined (TE_PE) && defined (O_secrel)
29 #define NUM_MD5_BYTES 16
31 #define FILE_ENTRY_PADDING 2
32 #define FILE_ENTRY_LENGTH (sizeof (struct file_checksum) + NUM_MD5_BYTES \
44 struct line_file
*next
;
46 struct line
*lines_head
, *lines_tail
;
47 unsigned int num_lines
;
52 struct line_block
*next
;
57 struct line_file
*files_head
, *files_tail
;
62 struct source_file
*next
;
66 uint8_t md5
[NUM_MD5_BYTES
];
69 static struct line_block
*blocks_head
= NULL
, *blocks_tail
= NULL
;
70 static struct source_file
*files_head
= NULL
, *files_tail
= NULL
;
71 static unsigned int num_source_files
= 0;
73 /* Return the size of the current fragment (taken from dwarf2dbg.c). */
75 get_frag_fix (fragS
*frag
, segT seg
)
82 for (fr
= seg_info (seg
)->frchainP
; fr
; fr
= fr
->frch_next
)
83 if (fr
->frch_last
== frag
)
84 return (char *) obstack_next_free (&fr
->frch_obstack
) - frag
->fr_literal
;
89 /* Emit a .secrel32 relocation. */
91 emit_secrel32_reloc (symbolS
*sym
)
95 memset (&exp
, 0, sizeof (exp
));
97 exp
.X_add_symbol
= sym
;
99 emit_expr (&exp
, sizeof (uint32_t));
102 /* Emit a .secidx relocation. */
104 emit_secidx_reloc (symbolS
*sym
)
108 memset (&exp
, 0, sizeof (exp
));
110 exp
.X_add_symbol
= sym
;
111 exp
.X_add_number
= 0;
112 emit_expr (&exp
, sizeof (uint16_t));
115 /* Write the DEBUG_S_STRINGTABLE subsection. */
117 write_string_table (void)
120 unsigned int padding
;
125 for (struct source_file
*sf
= files_head
; sf
; sf
= sf
->next
)
127 len
+= strlen (sf
->filename
) + 1;
131 padding
= 4 - (len
% 4);
135 ptr
= frag_more (sizeof (uint32_t) + sizeof (uint32_t) + len
+ padding
);
137 bfd_putl32 (DEBUG_S_STRINGTABLE
, ptr
);
138 ptr
+= sizeof (uint32_t);
139 bfd_putl32 (len
, ptr
);
140 ptr
+= sizeof (uint32_t);
147 for (struct source_file
*sf
= files_head
; sf
; sf
= sf
->next
)
149 size_t fn_len
= strlen (sf
->filename
);
151 sf
->string_pos
= ptr
- start
;
153 memcpy(ptr
, sf
->filename
, fn_len
+ 1);
157 memset (ptr
, 0, padding
);
160 /* Write the DEBUG_S_FILECHKSMS subsection. */
162 write_checksums (void)
167 len
= FILE_ENTRY_LENGTH
* num_source_files
;
169 ptr
= frag_more (sizeof (uint32_t) + sizeof (uint32_t) + len
);
171 bfd_putl32 (DEBUG_S_FILECHKSMS
, ptr
);
172 ptr
+= sizeof (uint32_t);
173 bfd_putl32 (len
, ptr
);
174 ptr
+= sizeof (uint32_t);
176 for (struct source_file
*sf
= files_head
; sf
; sf
= sf
->next
)
178 struct file_checksum fc
;
180 fc
.file_id
= sf
->string_pos
;
181 fc
.checksum_length
= NUM_MD5_BYTES
;
182 fc
.checksum_type
= CHKSUM_TYPE_MD5
;
184 memcpy (ptr
, &fc
, sizeof (struct file_checksum
));
185 ptr
+= sizeof (struct file_checksum
);
187 memcpy (ptr
, sf
->md5
, NUM_MD5_BYTES
);
188 ptr
+= NUM_MD5_BYTES
;
190 memset (ptr
, 0, FILE_ENTRY_PADDING
);
191 ptr
+= FILE_ENTRY_PADDING
;
195 /* Write the DEBUG_S_LINES subsection. */
197 write_lines_info (void)
201 struct line_block
*lb
;
202 struct line_file
*lf
;
209 bfd_putl32 (DEBUG_S_LINES
, frag_more (sizeof (uint32_t)));
211 len
= sizeof (struct cv_lines_header
);
213 for (lf
= lb
->files_head
; lf
; lf
= lf
->next
)
215 len
+= sizeof (struct cv_lines_block
);
216 len
+= sizeof (struct cv_line
) * lf
->num_lines
;
219 bfd_putl32 (len
, frag_more (sizeof (uint32_t)));
221 /* Write the header (struct cv_lines_header). We can't use a struct
222 for this as we're also emitting relocations. */
224 emit_secrel32_reloc (lb
->sym
);
225 emit_secidx_reloc (lb
->sym
);
227 ptr
= frag_more (len
- sizeof (uint32_t) - sizeof (uint16_t));
231 ptr
+= sizeof (uint16_t);
233 off
= lb
->files_head
->lines_head
->frag_offset
;
235 /* Length of region */
236 bfd_putl32 (get_frag_fix (lb
->frag
, lb
->seg
) - off
, ptr
);
237 ptr
+= sizeof (uint32_t);
239 while (lb
->files_head
)
241 struct cv_lines_block
*block
= (struct cv_lines_block
*) ptr
;
245 bfd_putl32(lf
->fileno
* FILE_ENTRY_LENGTH
, &block
->file_id
);
246 bfd_putl32(lf
->num_lines
, &block
->num_lines
);
247 bfd_putl32(sizeof (struct cv_lines_block
)
248 + (sizeof (struct cv_line
) * lf
->num_lines
),
251 ptr
+= sizeof (struct cv_lines_block
);
253 while (lf
->lines_head
)
256 struct cv_line
*l2
= (struct cv_line
*) ptr
;
260 /* Only the bottom 24 bits of line_no actually encode the
261 line number. The top bit is a flag meaning "is
264 bfd_putl32 (l
->frag_offset
- off
, &l2
->offset
);
265 bfd_putl32 (0x80000000 | (l
->lineno
& 0xffffff),
268 lf
->lines_head
= l
->next
;
272 ptr
+= sizeof (struct cv_line
);
275 lb
->files_head
= lf
->next
;
279 blocks_head
= lb
->next
;
285 /* Return the CodeView constant for the selected architecture. */
287 target_processor (void)
289 switch (stdoutput
->arch_info
->arch
)
292 if (stdoutput
->arch_info
->mach
& bfd_mach_x86_64
)
297 case bfd_arch_aarch64
:
305 /* Write the CodeView symbols, describing the object name and
306 assembler version. */
308 write_symbols_info (void)
310 static const char assembler
[] = "GNU AS " VERSION
;
312 char *path
= lrealpath (out_file_name
);
313 char *path2
= remap_debug_filename (path
);
314 size_t path_len
, padding
;
316 struct OBJNAMESYM objname
;
317 struct COMPILESYM3 compile3
;
323 path_len
= strlen (path
);
325 len
= sizeof (struct OBJNAMESYM
) + path_len
+ 1;
326 len
+= sizeof (struct COMPILESYM3
) + sizeof (assembler
);
329 padding
= 4 - (len
% 4);
335 ptr
= frag_more (sizeof (uint32_t) + sizeof (uint32_t) + len
);
337 bfd_putl32 (DEBUG_S_SYMBOLS
, ptr
);
338 ptr
+= sizeof (uint32_t);
339 bfd_putl32 (len
, ptr
);
340 ptr
+= sizeof (uint32_t);
342 /* Write S_OBJNAME entry. */
344 bfd_putl16 (sizeof (struct OBJNAMESYM
) - sizeof (uint16_t) + path_len
+ 1,
346 bfd_putl16 (S_OBJNAME
, &objname
.type
);
347 bfd_putl32 (0, &objname
.signature
);
349 memcpy (ptr
, &objname
, sizeof (struct OBJNAMESYM
));
350 ptr
+= sizeof (struct OBJNAMESYM
);
351 memcpy (ptr
, path
, path_len
+ 1);
356 /* Write S_COMPILE3 entry. */
358 bfd_putl16 (sizeof (struct COMPILESYM3
) - sizeof (uint16_t)
359 + sizeof (assembler
) + padding
, &compile3
.length
);
360 bfd_putl16 (S_COMPILE3
, &compile3
.type
);
361 bfd_putl32 (CV_CFL_MASM
, &compile3
.flags
);
362 bfd_putl16 (target_processor (), &compile3
.machine
);
363 bfd_putl16 (0, &compile3
.frontend_major
);
364 bfd_putl16 (0, &compile3
.frontend_minor
);
365 bfd_putl16 (0, &compile3
.frontend_build
);
366 bfd_putl16 (0, &compile3
.frontend_qfe
);
367 bfd_putl16 (0, &compile3
.backend_major
);
368 bfd_putl16 (0, &compile3
.backend_minor
);
369 bfd_putl16 (0, &compile3
.backend_build
);
370 bfd_putl16 (0, &compile3
.backend_qfe
);
372 memcpy (ptr
, &compile3
, sizeof (struct COMPILESYM3
));
373 ptr
+= sizeof (struct COMPILESYM3
);
374 memcpy (ptr
, assembler
, sizeof (assembler
));
375 ptr
+= sizeof (assembler
);
377 memset (ptr
, 0, padding
);
380 /* Processing of the file has finished, emit the .debug$S section. */
382 codeview_finish (void)
389 seg
= subseg_new (".debug$S", 0);
391 bfd_set_section_flags (seg
, SEC_READONLY
| SEC_NEVER_LOAD
);
393 bfd_putl32 (CV_SIGNATURE_C13
, frag_more (sizeof (uint32_t)));
395 write_string_table ();
398 write_symbols_info ();
401 /* Assign a new index number for the given file, or return the existing
402 one if already assigned. */
404 get_fileno (const char *file
)
406 struct source_file
*sf
;
407 char *path
= lrealpath (file
);
408 char *path2
= remap_debug_filename (path
);
415 path_len
= strlen (path
);
417 for (sf
= files_head
; sf
; sf
= sf
->next
)
419 if (path_len
== strlen (sf
->filename
)
420 && !filename_ncmp (sf
->filename
, path
, path_len
))
427 sf
= xmalloc (sizeof (struct source_file
));
430 sf
->num
= num_source_files
;
433 f
= fopen (file
, "r");
435 as_fatal (_("could not open %s for reading"), file
);
437 if (md5_stream (f
, sf
->md5
))
440 as_fatal (_("md5_stream failed"));
448 files_tail
->next
= sf
;
454 return num_source_files
- 1;
457 /* Called for each new line in asm file. */
459 codeview_generate_asm_lineno (void)
466 struct line_block
*lb
;
467 struct line_file
*lf
;
469 file
= as_where (&lineno
);
471 filenr
= get_fileno (file
);
473 if (!blocks_tail
|| blocks_tail
->frag
!= frag_now
)
475 static int label_num
= 0;
478 sprintf (name
, ".Loc.%u", label_num
);
480 sym
= symbol_new (name
, now_seg
, frag_now
, frag_now_fix ());
482 lb
= xmalloc (sizeof (struct line_block
));
485 lb
->subseg
= now_subseg
;
488 lb
->files_head
= lb
->files_tail
= NULL
;
493 blocks_tail
->next
= lb
;
502 if (!lb
->files_tail
|| lb
->files_tail
->fileno
!= filenr
)
504 lf
= xmalloc (sizeof (struct line_file
));
507 lf
->lines_head
= lf
->lines_tail
= NULL
;
513 lb
->files_tail
->next
= lf
;
522 l
= xmalloc (sizeof (struct line
));
525 l
->frag_offset
= frag_now_fix ();
530 lf
->lines_tail
->next
= l
;
539 codeview_finish (void)
544 codeview_generate_asm_lineno (void)
548 #endif /* TE_PE && O_secrel */