xref: /netbsd-src/external/gpl3/binutils/dist/gas/codeview.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* codeview.c - CodeView debug support
2    Copyright (C) 2022-2024 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
get_frag_fix(fragS * frag,segT seg)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
emit_secrel32_reloc(symbolS * sym)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
emit_secidx_reloc(symbolS * sym)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
write_string_table(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
write_checksums(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
write_lines_info(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
target_processor(void)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
write_symbols_info(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
codeview_finish(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
get_fileno(const char * file)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
codeview_generate_asm_lineno(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
codeview_finish(void)539 codeview_finish (void)
540 {
541 }
542 
543 void
codeview_generate_asm_lineno(void)544 codeview_generate_asm_lineno (void)
545 {
546 }
547 
548 #endif /* TE_PE && O_secrel */
549