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 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 */ 549