Remove path name from test case
[binutils-gdb.git] / gas / codeview.c
1 /* codeview.c - CodeView debug support
2 Copyright (C) 2022-2023 Free Software Foundation, Inc.
3
4 This file is part of GAS, the GNU Assembler.
5
6 GAS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
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.
15
16 You should have received a copy of the GNU General Public License
17 along with GAS; see the file COPYING. If not, write to the Free
18 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
19 02110-1301, USA. */
20
21 #include "as.h"
22 #include "codeview.h"
23 #include "subsegs.h"
24 #include "filenames.h"
25 #include "md5.h"
26
27 #if defined (TE_PE) && defined (O_secrel)
28
29 #define NUM_MD5_BYTES 16
30
31 #define FILE_ENTRY_PADDING 2
32 #define FILE_ENTRY_LENGTH (sizeof (struct file_checksum) + NUM_MD5_BYTES \
33 + FILE_ENTRY_PADDING)
34
35 struct line
36 {
37 struct line *next;
38 unsigned int lineno;
39 addressT frag_offset;
40 };
41
42 struct line_file
43 {
44 struct line_file *next;
45 unsigned int fileno;
46 struct line *lines_head, *lines_tail;
47 unsigned int num_lines;
48 };
49
50 struct line_block
51 {
52 struct line_block *next;
53 segT seg;
54 unsigned int subseg;
55 fragS *frag;
56 symbolS *sym;
57 struct line_file *files_head, *files_tail;
58 };
59
60 struct source_file
61 {
62 struct source_file *next;
63 unsigned int num;
64 char *filename;
65 uint32_t string_pos;
66 uint8_t md5[NUM_MD5_BYTES];
67 };
68
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;
72
73 /* Return the size of the current fragment (taken from dwarf2dbg.c). */
74 static offsetT
75 get_frag_fix (fragS *frag, segT seg)
76 {
77 frchainS *fr;
78
79 if (frag->fr_next)
80 return frag->fr_fix;
81
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;
85
86 abort ();
87 }
88
89 /* Emit a .secrel32 relocation. */
90 static void
91 emit_secrel32_reloc (symbolS *sym)
92 {
93 expressionS exp;
94
95 memset (&exp, 0, sizeof (exp));
96 exp.X_op = O_secrel;
97 exp.X_add_symbol = sym;
98 exp.X_add_number = 0;
99 emit_expr (&exp, sizeof (uint32_t));
100 }
101
102 /* Emit a .secidx relocation. */
103 static void
104 emit_secidx_reloc (symbolS *sym)
105 {
106 expressionS exp;
107
108 memset (&exp, 0, sizeof (exp));
109 exp.X_op = O_secidx;
110 exp.X_add_symbol = sym;
111 exp.X_add_number = 0;
112 emit_expr (&exp, sizeof (uint16_t));
113 }
114
115 /* Write the DEBUG_S_STRINGTABLE subsection. */
116 static void
117 write_string_table (void)
118 {
119 uint32_t len;
120 unsigned int padding;
121 char *ptr, *start;
122
123 len = 1;
124
125 for (struct source_file *sf = files_head; sf; sf = sf->next)
126 {
127 len += strlen (sf->filename) + 1;
128 }
129
130 if (len % 4)
131 padding = 4 - (len % 4);
132 else
133 padding = 0;
134
135 ptr = frag_more (sizeof (uint32_t) + sizeof (uint32_t) + len + padding);
136
137 bfd_putl32 (DEBUG_S_STRINGTABLE, ptr);
138 ptr += sizeof (uint32_t);
139 bfd_putl32 (len, ptr);
140 ptr += sizeof (uint32_t);
141
142 start = ptr;
143
144 *ptr = 0;
145 ptr++;
146
147 for (struct source_file *sf = files_head; sf; sf = sf->next)
148 {
149 size_t fn_len = strlen (sf->filename);
150
151 sf->string_pos = ptr - start;
152
153 memcpy(ptr, sf->filename, fn_len + 1);
154 ptr += fn_len + 1;
155 }
156
157 memset (ptr, 0, padding);
158 }
159
160 /* Write the DEBUG_S_FILECHKSMS subsection. */
161 static void
162 write_checksums (void)
163 {
164 uint32_t len;
165 char *ptr;
166
167 len = FILE_ENTRY_LENGTH * num_source_files;
168
169 ptr = frag_more (sizeof (uint32_t) + sizeof (uint32_t) + len);
170
171 bfd_putl32 (DEBUG_S_FILECHKSMS, ptr);
172 ptr += sizeof (uint32_t);
173 bfd_putl32 (len, ptr);
174 ptr += sizeof (uint32_t);
175
176 for (struct source_file *sf = files_head; sf; sf = sf->next)
177 {
178 struct file_checksum fc;
179
180 fc.file_id = sf->string_pos;
181 fc.checksum_length = NUM_MD5_BYTES;
182 fc.checksum_type = CHKSUM_TYPE_MD5;
183
184 memcpy (ptr, &fc, sizeof (struct file_checksum));
185 ptr += sizeof (struct file_checksum);
186
187 memcpy (ptr, sf->md5, NUM_MD5_BYTES);
188 ptr += NUM_MD5_BYTES;
189
190 memset (ptr, 0, FILE_ENTRY_PADDING);
191 ptr += FILE_ENTRY_PADDING;
192 }
193 }
194
195 /* Write the DEBUG_S_LINES subsection. */
196 static void
197 write_lines_info (void)
198 {
199 while (blocks_head)
200 {
201 struct line_block *lb;
202 struct line_file *lf;
203 uint32_t len;
204 uint32_t off;
205 char *ptr;
206
207 lb = blocks_head;
208
209 bfd_putl32 (DEBUG_S_LINES, frag_more (sizeof (uint32_t)));
210
211 len = sizeof (struct cv_lines_header);
212
213 for (lf = lb->files_head; lf; lf = lf->next)
214 {
215 len += sizeof (struct cv_lines_block);
216 len += sizeof (struct cv_line) * lf->num_lines;
217 }
218
219 bfd_putl32 (len, frag_more (sizeof (uint32_t)));
220
221 /* Write the header (struct cv_lines_header). We can't use a struct
222 for this as we're also emitting relocations. */
223
224 emit_secrel32_reloc (lb->sym);
225 emit_secidx_reloc (lb->sym);
226
227 ptr = frag_more (len - sizeof (uint32_t) - sizeof (uint16_t));
228
229 /* Flags */
230 bfd_putl16 (0, ptr);
231 ptr += sizeof (uint16_t);
232
233 off = lb->files_head->lines_head->frag_offset;
234
235 /* Length of region */
236 bfd_putl32 (get_frag_fix (lb->frag, lb->seg) - off, ptr);
237 ptr += sizeof (uint32_t);
238
239 while (lb->files_head)
240 {
241 struct cv_lines_block *block = (struct cv_lines_block *) ptr;
242
243 lf = lb->files_head;
244
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),
249 &block->length);
250
251 ptr += sizeof (struct cv_lines_block);
252
253 while (lf->lines_head)
254 {
255 struct line *l;
256 struct cv_line *l2 = (struct cv_line *) ptr;
257
258 l = lf->lines_head;
259
260 /* Only the bottom 24 bits of line_no actually encode the
261 line number. The top bit is a flag meaning "is
262 a statement". */
263
264 bfd_putl32 (l->frag_offset - off, &l2->offset);
265 bfd_putl32 (0x80000000 | (l->lineno & 0xffffff),
266 &l2->line_no);
267
268 lf->lines_head = l->next;
269
270 free(l);
271
272 ptr += sizeof (struct cv_line);
273 }
274
275 lb->files_head = lf->next;
276 free (lf);
277 }
278
279 blocks_head = lb->next;
280
281 free (lb);
282 }
283 }
284
285 /* Return the CodeView constant for the selected architecture. */
286 static uint16_t
287 target_processor (void)
288 {
289 switch (stdoutput->arch_info->arch)
290 {
291 case bfd_arch_i386:
292 if (stdoutput->arch_info->mach & bfd_mach_x86_64)
293 return CV_CFL_X64;
294 else
295 return CV_CFL_80386;
296
297 case bfd_arch_aarch64:
298 return CV_CFL_ARM64;
299
300 default:
301 return 0;
302 }
303 }
304
305 /* Write the CodeView symbols, describing the object name and
306 assembler version. */
307 static void
308 write_symbols_info (void)
309 {
310 static const char assembler[] = "GNU AS " VERSION;
311
312 char *path = lrealpath (out_file_name);
313 char *path2 = remap_debug_filename (path);
314 size_t path_len, padding;
315 uint32_t len;
316 struct OBJNAMESYM objname;
317 struct COMPILESYM3 compile3;
318 char *ptr;
319
320 free (path);
321 path = path2;
322
323 path_len = strlen (path);
324
325 len = sizeof (struct OBJNAMESYM) + path_len + 1;
326 len += sizeof (struct COMPILESYM3) + sizeof (assembler);
327
328 if (len % 4)
329 padding = 4 - (len % 4);
330 else
331 padding = 0;
332
333 len += padding;
334
335 ptr = frag_more (sizeof (uint32_t) + sizeof (uint32_t) + len);
336
337 bfd_putl32 (DEBUG_S_SYMBOLS, ptr);
338 ptr += sizeof (uint32_t);
339 bfd_putl32 (len, ptr);
340 ptr += sizeof (uint32_t);
341
342 /* Write S_OBJNAME entry. */
343
344 bfd_putl16 (sizeof (struct OBJNAMESYM) - sizeof (uint16_t) + path_len + 1,
345 &objname.length);
346 bfd_putl16 (S_OBJNAME, &objname.type);
347 bfd_putl32 (0, &objname.signature);
348
349 memcpy (ptr, &objname, sizeof (struct OBJNAMESYM));
350 ptr += sizeof (struct OBJNAMESYM);
351 memcpy (ptr, path, path_len + 1);
352 ptr += path_len + 1;
353
354 free (path);
355
356 /* Write S_COMPILE3 entry. */
357
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);
371
372 memcpy (ptr, &compile3, sizeof (struct COMPILESYM3));
373 ptr += sizeof (struct COMPILESYM3);
374 memcpy (ptr, assembler, sizeof (assembler));
375 ptr += sizeof (assembler);
376
377 memset (ptr, 0, padding);
378 }
379
380 /* Processing of the file has finished, emit the .debug$S section. */
381 void
382 codeview_finish (void)
383 {
384 segT seg;
385
386 if (!blocks_head)
387 return;
388
389 seg = subseg_new (".debug$S", 0);
390
391 bfd_set_section_flags (seg, SEC_READONLY | SEC_NEVER_LOAD);
392
393 bfd_putl32 (CV_SIGNATURE_C13, frag_more (sizeof (uint32_t)));
394
395 write_string_table ();
396 write_checksums ();
397 write_lines_info ();
398 write_symbols_info ();
399 }
400
401 /* Assign a new index number for the given file, or return the existing
402 one if already assigned. */
403 static unsigned int
404 get_fileno (const char *file)
405 {
406 struct source_file *sf;
407 char *path = lrealpath (file);
408 char *path2 = remap_debug_filename (path);
409 size_t path_len;
410 FILE *f;
411
412 free (path);
413 path = path2;
414
415 path_len = strlen (path);
416
417 for (sf = files_head; sf; sf = sf->next)
418 {
419 if (path_len == strlen (sf->filename)
420 && !filename_ncmp (sf->filename, path, path_len))
421 {
422 free (path);
423 return sf->num;
424 }
425 }
426
427 sf = xmalloc (sizeof (struct source_file));
428
429 sf->next = NULL;
430 sf->num = num_source_files;
431 sf->filename = path;
432
433 f = fopen (file, "r");
434 if (!f)
435 as_fatal (_("could not open %s for reading"), file);
436
437 if (md5_stream (f, sf->md5))
438 {
439 fclose(f);
440 as_fatal (_("md5_stream failed"));
441 }
442
443 fclose(f);
444
445 if (!files_head)
446 files_head = sf;
447 else
448 files_tail->next = sf;
449
450 files_tail = sf;
451
452 num_source_files++;
453
454 return num_source_files - 1;
455 }
456
457 /* Called for each new line in asm file. */
458 void
459 codeview_generate_asm_lineno (void)
460 {
461 const char *file;
462 unsigned int filenr;
463 unsigned int lineno;
464 struct line *l;
465 symbolS *sym = NULL;
466 struct line_block *lb;
467 struct line_file *lf;
468
469 file = as_where (&lineno);
470
471 filenr = get_fileno (file);
472
473 if (!blocks_tail || blocks_tail->frag != frag_now)
474 {
475 static int label_num = 0;
476 char name[32];
477
478 sprintf (name, ".Loc.%u", label_num);
479 label_num++;
480 sym = symbol_new (name, now_seg, frag_now, frag_now_fix ());
481
482 lb = xmalloc (sizeof (struct line_block));
483 lb->next = NULL;
484 lb->seg = now_seg;
485 lb->subseg = now_subseg;
486 lb->frag = frag_now;
487 lb->sym = sym;
488 lb->files_head = lb->files_tail = NULL;
489
490 if (!blocks_head)
491 blocks_head = lb;
492 else
493 blocks_tail->next = lb;
494
495 blocks_tail = lb;
496 }
497 else
498 {
499 lb = blocks_tail;
500 }
501
502 if (!lb->files_tail || lb->files_tail->fileno != filenr)
503 {
504 lf = xmalloc (sizeof (struct line_file));
505 lf->next = NULL;
506 lf->fileno = filenr;
507 lf->lines_head = lf->lines_tail = NULL;
508 lf->num_lines = 0;
509
510 if (!lb->files_head)
511 lb->files_head = lf;
512 else
513 lb->files_tail->next = lf;
514
515 lb->files_tail = lf;
516 }
517 else
518 {
519 lf = lb->files_tail;
520 }
521
522 l = xmalloc (sizeof (struct line));
523 l->next = NULL;
524 l->lineno = lineno;
525 l->frag_offset = frag_now_fix ();
526
527 if (!lf->lines_head)
528 lf->lines_head = l;
529 else
530 lf->lines_tail->next = l;
531
532 lf->lines_tail = l;
533 lf->num_lines++;
534 }
535
536 #else
537
538 void
539 codeview_finish (void)
540 {
541 }
542
543 void
544 codeview_generate_asm_lineno (void)
545 {
546 }
547
548 #endif /* TE_PE && O_secrel */