(root)/
binutils-2.41/
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 */