Wolfgang Thallergcc16 merge934c3885 months agoHistory
632 lines · 13.2 KB · C
RawDownload
/* codeview.c - CodeView debug support   Copyright (C) 2022-2026 Free Software Foundation, Inc.    This file is part of GAS, the GNU Assembler.    GAS is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 3, or (at your option)   any later version.    GAS is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.    You should have received a copy of the GNU General Public License   along with GAS; see the file COPYING.  If not, write to the Free   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA   02110-1301, USA.  */ #include "as.h"#include "codeview.h"#include "subsegs.h"#include "filenames.h"#include "md5.h" #if defined (TE_PE) && defined (O_secrel) #define NUM_MD5_BYTES       	16 #define FILE_ENTRY_PADDING	2#define FILE_ENTRY_LENGTH	(sizeof (struct file_checksum) + NUM_MD5_BYTES \				 + FILE_ENTRY_PADDING) struct line{  struct line *next;  unsigned int lineno;  addressT frag_offset;}; struct line_file{  struct line_file *next;  unsigned int fileno;  struct line *lines_head, *lines_tail;  unsigned int num_lines;}; struct line_block{  struct line_block *next;  segT seg;  unsigned int subseg;  fragS *frag;  symbolS *sym;  struct line_file *files_head, *files_tail;}; struct source_file{  struct source_file *next;  unsigned int num;  char *filename;  uint32_t string_pos;  uint8_t md5[NUM_MD5_BYTES];}; static struct line_block *blocks_head = NULL, *blocks_tail = NULL;static struct source_file *files_head = NULL, *files_tail = NULL;static unsigned int num_source_files = 0; /* Return the size of the current fragment (taken from dwarf2dbg.c).  */static offsetTget_frag_fix (fragS *frag, segT seg){  frchainS *fr;   if (frag->fr_next)    return frag->fr_fix;   for (fr = seg_info (seg)->frchainP; fr; fr = fr->frch_next)    if (fr->frch_last == frag)      return (char *) obstack_next_free (&fr->frch_obstack) - frag->fr_literal;   abort ();} /* Emit a .secrel32 relocation.  */static voidemit_secrel32_reloc (symbolS *sym){  expressionS exp;   memset (&exp, 0, sizeof (exp));  exp.X_op = O_secrel;  exp.X_add_symbol = sym;  exp.X_add_number = 0;  emit_expr (&exp, sizeof (uint32_t));} /* Emit a .secidx relocation.  */static voidemit_secidx_reloc (symbolS *sym){  expressionS exp;   memset (&exp, 0, sizeof (exp));  exp.X_op = O_secidx;  exp.X_add_symbol = sym;  exp.X_add_number = 0;  emit_expr (&exp, sizeof (uint16_t));} /* Write the DEBUG_S_STRINGTABLE subsection.  */static voidwrite_string_table (void){  uint32_t len;  unsigned int padding;  char *ptr, *start;   len = 1;   for (struct source_file *sf = files_head; sf; sf = sf->next)    {      len += strlen (sf->filename) + 1;    }   if (len % 4)    padding = 4 - (len % 4);  else    padding = 0;   ptr = frag_more (sizeof (uint32_t) + sizeof (uint32_t) + len + padding);   bfd_putl32 (DEBUG_S_STRINGTABLE, ptr);  ptr += sizeof (uint32_t);  bfd_putl32 (len, ptr);  ptr += sizeof (uint32_t);   start = ptr;   *ptr = 0;  ptr++;   for (struct source_file *sf = files_head; sf; sf = sf->next)    {      size_t fn_len = strlen (sf->filename);       sf->string_pos = ptr - start;       memcpy(ptr, sf->filename, fn_len + 1);      ptr += fn_len + 1;    }   memset (ptr, 0, padding);} /* Write the DEBUG_S_FILECHKSMS subsection.  */static voidwrite_checksums (void){  uint32_t len;  char *ptr;   len = FILE_ENTRY_LENGTH * num_source_files;   ptr = frag_more (sizeof (uint32_t) + sizeof (uint32_t) + len);   bfd_putl32 (DEBUG_S_FILECHKSMS, ptr);  ptr += sizeof (uint32_t);  bfd_putl32 (len, ptr);  ptr += sizeof (uint32_t);   for (struct source_file *sf = files_head; sf; sf = sf->next)    {      struct file_checksum fc;       fc.file_id = sf->string_pos;      fc.checksum_length = NUM_MD5_BYTES;      fc.checksum_type = CHKSUM_TYPE_MD5;       memcpy (ptr, &fc, sizeof (struct file_checksum));      ptr += sizeof (struct file_checksum);       memcpy (ptr, sf->md5, NUM_MD5_BYTES);      ptr += NUM_MD5_BYTES;       memset (ptr, 0, FILE_ENTRY_PADDING);      ptr += FILE_ENTRY_PADDING;    }} /* Write the DEBUG_S_LINES subsection.  */static voidwrite_lines_info (void){  while (blocks_head)    {      struct line_block *lb;      struct line_file *lf;      uint32_t len;      uint32_t off;      char *ptr;       lb = blocks_head;       bfd_putl32 (DEBUG_S_LINES, frag_more (sizeof (uint32_t)));       len = sizeof (struct cv_lines_header);       for (lf = lb->files_head; lf; lf = lf->next)	{	  len += sizeof (struct cv_lines_block);	  len += sizeof (struct cv_line) * lf->num_lines;	}       bfd_putl32 (len, frag_more (sizeof (uint32_t)));       /* Write the header (struct cv_lines_header).  We can't use a struct	 for this as we're also emitting relocations.  */       emit_secrel32_reloc (lb->sym);      emit_secidx_reloc (lb->sym);       ptr = frag_more (len - sizeof (uint32_t) - sizeof (uint16_t));       /* Flags */      bfd_putl16 (0, ptr);      ptr += sizeof (uint16_t);       off = lb->files_head->lines_head->frag_offset;       /* Length of region */      bfd_putl32 (get_frag_fix (lb->frag, lb->seg) - off, ptr);      ptr += sizeof (uint32_t);       while (lb->files_head)	{	  struct cv_lines_block *block = (struct cv_lines_block *) ptr; 	  lf = lb->files_head; 	  bfd_putl32(lf->fileno * FILE_ENTRY_LENGTH, &block->file_id);	  bfd_putl32(lf->num_lines, &block->num_lines);	  bfd_putl32(sizeof (struct cv_lines_block)		     + (sizeof (struct cv_line) * lf->num_lines),		     &block->length); 	  ptr += sizeof (struct cv_lines_block); 	  while (lf->lines_head)	    {	      struct line *l;	      struct cv_line *l2 = (struct cv_line *) ptr; 	      l = lf->lines_head; 	      /* Only the bottom 24 bits of line_no actually encode the		 line number.  The top bit is a flag meaning "is		 a statement".  */ 	      bfd_putl32 (l->frag_offset - off, &l2->offset);	      bfd_putl32 (0x80000000 | (l->lineno & 0xffffff),			  &l2->line_no); 	      lf->lines_head = l->next; 	      free(l); 	      ptr += sizeof (struct cv_line);	    } 	  lb->files_head = lf->next;	  free (lf);	}       blocks_head = lb->next;       free (lb);    }} /* Return the CodeView constant for the selected architecture.  */static uint16_ttarget_processor (void){  switch (stdoutput->arch_info->arch)    {    case bfd_arch_i386:      if (stdoutput->arch_info->mach & bfd_mach_x86_64)	return CV_CFL_X64;      else	return CV_CFL_80386;     case bfd_arch_aarch64:      return CV_CFL_ARM64;     default:      return 0;    }} /* Write the CodeView symbols, describing the object name and   assembler version.  */static voidwrite_symbols_info (void){  static const char assembler[] = "GNU AS " VERSION;   char *path = lrealpath (out_file_name);  char *path2 = remap_debug_filename (path);  size_t path_len, padding;  uint32_t len;  struct OBJNAMESYM objname;  struct COMPILESYM3 compile3;  char *ptr;   free (path);  path = path2;   path_len = strlen (path);   len = sizeof (struct OBJNAMESYM) + path_len + 1;  len += sizeof (struct COMPILESYM3) + sizeof (assembler);   if (len % 4)    padding = 4 - (len % 4);  else    padding = 0;   len += padding;   ptr = frag_more (sizeof (uint32_t) + sizeof (uint32_t) + len);   bfd_putl32 (DEBUG_S_SYMBOLS, ptr);  ptr += sizeof (uint32_t);  bfd_putl32 (len, ptr);  ptr += sizeof (uint32_t);   /* Write S_OBJNAME entry.  */   bfd_putl16 (sizeof (struct OBJNAMESYM) - sizeof (uint16_t) + path_len + 1,	      &objname.length);  bfd_putl16 (S_OBJNAME, &objname.type);  bfd_putl32 (0, &objname.signature);   memcpy (ptr, &objname, sizeof (struct OBJNAMESYM));  ptr += sizeof (struct OBJNAMESYM);  memcpy (ptr, path, path_len + 1);  ptr += path_len + 1;   free (path);   /* Write S_COMPILE3 entry.  */   bfd_putl16 (sizeof (struct COMPILESYM3) - sizeof (uint16_t)	      + sizeof (assembler) + padding, &compile3.length);  bfd_putl16 (S_COMPILE3, &compile3.type);  bfd_putl32 (CV_CFL_MASM, &compile3.flags);  bfd_putl16 (target_processor (), &compile3.machine);  bfd_putl16 (0, &compile3.frontend_major);  bfd_putl16 (0, &compile3.frontend_minor);  bfd_putl16 (0, &compile3.frontend_build);  bfd_putl16 (0, &compile3.frontend_qfe);  bfd_putl16 (0, &compile3.backend_major);  bfd_putl16 (0, &compile3.backend_minor);  bfd_putl16 (0, &compile3.backend_build);  bfd_putl16 (0, &compile3.backend_qfe);   memcpy (ptr, &compile3, sizeof (struct COMPILESYM3));  ptr += sizeof (struct COMPILESYM3);  memcpy (ptr, assembler, sizeof (assembler));  ptr += sizeof (assembler);   memset (ptr, 0, padding);} /* Processing of the file has finished, emit the .debug$S section.  */voidcodeview_finish (void){  segT seg;   if (!blocks_head)    return;   seg = subseg_new (".debug$S", 0);   bfd_set_section_flags (seg, SEC_READONLY | SEC_NEVER_LOAD);   bfd_putl32 (CV_SIGNATURE_C13, frag_more (sizeof (uint32_t)));   write_string_table ();  write_checksums ();  write_lines_info ();  write_symbols_info ();} /* Assign a new index number for the given file, or return the existing   one if already assigned.  */static unsigned intget_fileno (const char *file){  struct source_file *sf;  char *path = lrealpath (file);  char *path2 = remap_debug_filename (path);  size_t path_len;  FILE *f;   free (path);  path = path2;   path_len = strlen (path);   for (sf = files_head; sf; sf = sf->next)    {      if (path_len == strlen (sf->filename)	  && !filename_ncmp (sf->filename, path, path_len))	{	  free (path);	  return sf->num;	}    }   sf = xmalloc (sizeof (struct source_file));   sf->next = NULL;  sf->num = num_source_files;  sf->filename = path;   f = fopen (file, "r");  if (!f)    as_fatal (_("could not open %s for reading"), file);   if (md5_stream (f, sf->md5))    {      fclose(f);      as_fatal (_("md5_stream failed"));    }   fclose(f);   if (!files_head)    files_head = sf;  else    files_tail->next = sf;   files_tail = sf;   num_source_files++;   return num_source_files - 1;} /* Called for each new line in asm file.  */voidcodeview_generate_asm_lineno (void){  const char *file;  unsigned int filenr;  unsigned int lineno;  struct line *l;  symbolS *sym = NULL;  struct line_block *lb;  struct line_file *lf;   file = as_where (&lineno);   filenr = get_fileno (file);   if (!blocks_tail || blocks_tail->frag != frag_now)    {      static int label_num = 0;      char name[32];       sprintf (name, ".Loc.%u", label_num);      label_num++;      sym = symbol_new (name, now_seg, frag_now, frag_now_fix ());       lb = xmalloc (sizeof (struct line_block));      lb->next = NULL;      lb->seg = now_seg;      lb->subseg = now_subseg;      lb->frag = frag_now;      lb->sym = sym;      lb->files_head = lb->files_tail = NULL;       if (!blocks_head)	blocks_head = lb;      else	blocks_tail->next = lb;       blocks_tail = lb;    }  else    {      lb = blocks_tail;    }

Lines 1–500 of 632.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t