Home | History | Annotate | Download | only in libdw
      1 /* Return line number information of CU.
      2    Copyright (C) 2004 Red Hat, Inc.
      3    Written by Ulrich Drepper <drepper (at) redhat.com>, 2004.
      4 
      5    This program is Open Source software; you can redistribute it and/or
      6    modify it under the terms of the Open Software License version 1.0 as
      7    published by the Open Source Initiative.
      8 
      9    You should have received a copy of the Open Software License along
     10    with this program; if not, you may obtain a copy of the Open Software
     11    License version 1.0 from http://www.opensource.org/licenses/osl.php or
     12    by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
     13    3001 King Ranch Road, Ukiah, CA 95482.   */
     14 
     15 #ifdef HAVE_CONFIG_H
     16 # include <config.h>
     17 #endif
     18 
     19 #include <assert.h>
     20 #include <stdlib.h>
     21 #include <string.h>
     22 #include "dwarf.h"
     23 #include "libdwP.h"
     24 
     25 
     26 struct filelist
     27 {
     28   Dwarf_Fileinfo info;
     29   struct filelist *next;
     30 };
     31 
     32 struct linelist
     33 {
     34   Dwarf_Line line;
     35   struct linelist *next;
     36 };
     37 
     38 
     39 /* Adds a new line to the matrix.  We cannot definte a function because
     40    we want to use alloca.  */
     41 #define NEW_LINE(end_seq) \
     42   do {									      \
     43     /* Add the new line.  */						      \
     44     new_line = (struct linelist *) alloca (sizeof (struct linelist));	      \
     45 									      \
     46     /* Set the line information.  */					      \
     47     new_line->line.addr = address;					      \
     48     new_line->line.file = file;						      \
     49     new_line->line.line = line;						      \
     50     new_line->line.column = column;					      \
     51     new_line->line.is_stmt = is_stmt;					      \
     52     new_line->line.basic_block = basic_block;				      \
     53     new_line->line.end_sequence = end_seq;				      \
     54     new_line->line.prologue_end = prologue_end;				      \
     55     new_line->line.epilogue_begin = epilogue_begin;			      \
     56 									      \
     57     new_line->next = linelist;						      \
     58     linelist = new_line;						      \
     59     ++nlinelist;							      \
     60   } while (0)
     61 
     62 
     63 int
     64 dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
     65 {
     66   if (unlikely (cudie == NULL || dwarf_tag (cudie) != DW_TAG_compile_unit))
     67     return -1;
     68 
     69   int res = -1;
     70 
     71   /* Get the information if it is not already known.  */
     72   struct Dwarf_CU *const cu = cudie->cu;
     73   if (cu->lines == NULL)
     74     {
     75       /* Failsafe mode: no data found.  */
     76       cu->lines = (void *) -1l;
     77       cu->files = (void *) -1l;
     78 
     79       /* The die must have a statement list associated.  */
     80       Dwarf_Attribute stmt_list_mem;
     81       Dwarf_Attribute *stmt_list = dwarf_attr (cudie, DW_AT_stmt_list,
     82 					       &stmt_list_mem);
     83 
     84       /* Get the offset into the .debug_line section.  NB: this call
     85 	 also checks whether the previous dwarf_attr call failed.  */
     86       Dwarf_Word offset;
     87       if (dwarf_formudata (stmt_list, &offset) != 0)
     88 	goto out;
     89 
     90       Dwarf *dbg = cu->dbg;
     91       if (dbg->sectiondata[IDX_debug_line] == NULL)
     92 	{
     93 	  __libdw_seterrno (DWARF_E_NO_DEBUG_LINE);
     94 	  goto out;
     95 	}
     96       uint8_t *linep = dbg->sectiondata[IDX_debug_line]->d_buf + offset;
     97       uint8_t *lineendp = (dbg->sectiondata[IDX_debug_line]->d_buf
     98 			   + dbg->sectiondata[IDX_debug_line]->d_size);
     99 
    100       /* Get the compilation directory.  */
    101       Dwarf_Attribute compdir_attr_mem;
    102       Dwarf_Attribute *compdir_attr = dwarf_attr (cudie, DW_AT_comp_dir,
    103 						  &compdir_attr_mem);
    104       const char *comp_dir = dwarf_formstring (compdir_attr);
    105 
    106       if (unlikely (linep + 4 > lineendp))
    107 	{
    108 	invalid_data:
    109 	  __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
    110 	  goto out;
    111 	}
    112       Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
    113       unsigned int length = 4;
    114       if (unlikely (unit_length == 0xffffffff))
    115 	{
    116 	  if (unlikely (linep + 8 > lineendp))
    117 	    goto invalid_data;
    118 	  unit_length = read_8ubyte_unaligned_inc (dbg, linep);
    119 	  length = 8;
    120 	}
    121 
    122       /* Check whether we have enough room in the section.  */
    123       if (unit_length < 2 + length + 5 * 1
    124 	  || unlikely (linep + unit_length > lineendp))
    125 	goto invalid_data;
    126       lineendp = linep + unit_length;
    127 
    128       /* The next element of the header is the version identifier.  */
    129       uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
    130       if (unlikely (version != DWARF_VERSION))
    131 	{
    132 	  __libdw_seterrno (DWARF_E_VERSION);
    133 	  goto out;
    134 	}
    135 
    136       /* Next comes the header length.  */
    137       Dwarf_Word header_length;
    138       if (length == 4)
    139 	header_length = read_4ubyte_unaligned_inc (dbg, linep);
    140       else
    141 	header_length = read_8ubyte_unaligned_inc (dbg, linep);
    142       unsigned char *header_start = linep;
    143 
    144       /* Next the minimum instruction length.  */
    145       uint_fast8_t minimum_instr_len = *linep++;
    146 
    147         /* Then the flag determining the default value of the is_stmt
    148 	   register.  */
    149       uint_fast8_t default_is_stmt = *linep++;
    150 
    151       /* Now the line base.  */
    152       int_fast8_t line_base = *((int_fast8_t *) linep);
    153       ++linep;
    154 
    155       /* And the line range.  */
    156       uint_fast8_t line_range = *linep++;
    157 
    158       /* The opcode base.  */
    159       uint_fast8_t opcode_base = *linep++;
    160 
    161       /* Remember array with the standard opcode length (-1 to account for
    162 	 the opcode with value zero not being mentioned).  */
    163       uint8_t *standard_opcode_lengths = linep - 1;
    164       linep += opcode_base - 1;
    165       if (unlikely (linep >= lineendp))
    166 	goto invalid_data;
    167 
    168       /* First comes the list of directories.  Add the compilation
    169 	 directory first since the index zero is used for it.  */
    170       struct dirlist
    171       {
    172 	const char *dir;
    173 	size_t len;
    174 	struct dirlist *next;
    175       } comp_dir_elem =
    176 	{
    177 	  .dir = comp_dir,
    178 	  .len = comp_dir ? strlen (comp_dir) : 0,
    179 	  .next = NULL
    180 	};
    181       struct dirlist *dirlist = &comp_dir_elem;
    182       unsigned int ndirlist = 1;
    183 
    184       // XXX Directly construct array to conserve memory?
    185       while (*linep != 0)
    186 	{
    187 	  struct dirlist *new_dir =
    188 	    (struct dirlist *) alloca (sizeof (*new_dir));
    189 
    190 	  new_dir->dir = (char *) linep;
    191 	  uint8_t *endp = memchr (linep, '\0', lineendp - linep);
    192 	  if (endp == NULL)
    193 	    goto invalid_data;
    194 	  new_dir->len = endp - linep;
    195 	  new_dir->next = dirlist;
    196 	  dirlist = new_dir;
    197 	  ++ndirlist;
    198 	  linep = endp + 1;
    199 	}
    200       /* Skip the final NUL byte.  */
    201       ++linep;
    202 
    203       /* Rearrange the list in array form.  */
    204       struct dirlist **dirarray
    205 	= (struct dirlist **) alloca (ndirlist * sizeof (*dirarray));
    206       while (ndirlist-- > 0)
    207 	{
    208 	  dirarray[ndirlist] = dirlist;
    209 	  dirlist = dirlist->next;
    210 	}
    211 
    212         /* Now read the files.  */
    213       struct filelist null_file =
    214 	{
    215 	  .info =
    216 	  {
    217 	    .name = "???",
    218 	    .mtime = 0,
    219 	    .length = 0
    220 	  },
    221 	  .next = NULL
    222 	};
    223       struct filelist *filelist = &null_file;
    224       unsigned int nfilelist = 1;
    225 
    226       if (unlikely (linep >= lineendp))
    227 	goto invalid_data;
    228       while (*linep != 0)
    229 	{
    230 	  struct filelist *new_file =
    231 	    (struct filelist *) alloca (sizeof (*new_file));
    232 
    233 	  /* First comes the file name.  */
    234 	  char *fname = (char *) linep;
    235 	  uint8_t *endp = memchr (fname, '\0', lineendp - linep);
    236 	  if (endp == NULL)
    237 	    goto invalid_data;
    238 	  size_t fnamelen = endp - (uint8_t *) fname;
    239 	  linep = endp + 1;
    240 
    241 	  /* Then the index.  */
    242 	  Dwarf_Word diridx;
    243 	  get_uleb128 (diridx, linep);
    244 	  if (unlikely (diridx >= ndirlist))
    245 	    {
    246 	      __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
    247 	      goto out;
    248 	    }
    249 
    250 	  if (*fname == '/')
    251 	    /* It's an absolute path.  */
    252 	    new_file->info.name = fname;
    253 	  else
    254 	    {
    255 	      new_file->info.name = libdw_alloc (dbg, char, 1,
    256 						 dirarray[diridx]->len + 1
    257 						 + fnamelen + 1);
    258               char *cp = new_file->info.name;
    259 
    260               if (dirarray[diridx]->dir != NULL)
    261 		{
    262 		  /* This value could be NULL in case the DW_AT_comp_dir
    263 		     was not present.  We cannot do much in this case.
    264 		     The easiest thing is to convert the path in an
    265                    absolute path.  */
    266 		  cp = stpcpy (cp, dirarray[diridx]->dir);
    267 		}
    268               *cp++ = '/';
    269               strcpy (cp, fname);
    270 	      assert (strlen (new_file->info.name)
    271 		      < dirarray[diridx]->len + 1 + fnamelen + 1);
    272             }
    273 
    274 	  /* Next comes the modification time.  */
    275 	  get_uleb128 (new_file->info.mtime, linep);
    276 
    277 	  /* Finally the length of the file.  */
    278 	  get_uleb128 (new_file->info.length, linep);
    279 
    280 	  new_file->next = filelist;
    281 	  filelist = new_file;
    282 	  ++nfilelist;
    283 	}
    284       /* Skip the final NUL byte.  */
    285       ++linep;
    286 
    287       /* Consistency check.  */
    288       if (unlikely (linep != header_start + header_length))
    289 	{
    290 	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
    291 	  goto out;
    292 	}
    293 
    294         /* We are about to process the statement program.  Initialize the
    295 	   state machine registers (see 6.2.2 in the v2.1 specification).  */
    296       Dwarf_Word address = 0;
    297       size_t file = 1;
    298       size_t line = 1;
    299       size_t column = 0;
    300       uint_fast8_t is_stmt = default_is_stmt;
    301       int basic_block = 0;
    302       int prologue_end = 0;
    303       int epilogue_begin = 0;
    304 
    305         /* Process the instructions.  */
    306       struct linelist *linelist = NULL;
    307       unsigned int nlinelist = 0;
    308       while (linep < lineendp)
    309 	{
    310 	  struct linelist *new_line;
    311 	  unsigned int opcode;
    312 	  unsigned int u128;
    313 	  int s128;
    314 
    315 	  /* Read the opcode.  */
    316 	  opcode = *linep++;
    317 
    318 	  /* Is this a special opcode?  */
    319 	  if (likely (opcode >= opcode_base))
    320 	    {
    321 	      /* Yes.  Handling this is quite easy since the opcode value
    322 		 is computed with
    323 
    324 		 opcode = (desired line increment - line_base)
    325 		           + (line_range * address advance) + opcode_base
    326 	      */
    327 	      int line_increment = (line_base
    328 				    + (opcode - opcode_base) % line_range);
    329 	      unsigned int address_increment = (minimum_instr_len
    330 						* ((opcode - opcode_base)
    331 						   / line_range));
    332 
    333 	      /* Perform the increments.  */
    334 	      line += line_increment;
    335 	      address += address_increment;
    336 
    337 	      /* Add a new line with the current state machine values.  */
    338 	      NEW_LINE (0);
    339 
    340 	      /* Reset the flags.  */
    341 	      basic_block = 0;
    342 	      prologue_end = 0;
    343 	      epilogue_begin = 0;
    344 	    }
    345 	  else if (opcode == 0)
    346 	    {
    347 	      /* This an extended opcode.  */
    348 	      if (unlikely (linep + 2 > lineendp))
    349 		goto invalid_data;
    350 
    351 	      /* The length.  */
    352 	      unsigned int len = *linep++;
    353 
    354 	      if (unlikely (linep + len > lineendp))
    355 		goto invalid_data;
    356 
    357 	      /* The sub-opcode.  */
    358 	      opcode = *linep++;
    359 
    360 	      switch (opcode)
    361 		{
    362 		case DW_LNE_end_sequence:
    363 		  /* Add a new line with the current state machine values.
    364 		     The is the end of the sequence.  */
    365 		  NEW_LINE (1);
    366 
    367 		  /* Reset the registers.  */
    368 		  address = 0;
    369 		  file = 1;
    370 		  line = 1;
    371 		  column = 0;
    372 		  is_stmt = default_is_stmt;
    373 		  basic_block = 0;
    374 		  prologue_end = 0;
    375 		  epilogue_begin = 0;
    376 		  break;
    377 
    378 		case DW_LNE_set_address:
    379 		  /* The value is an address.  The size is defined as
    380 		     apporiate for the target machine.  We use the
    381 		     address size field from the CU header.  */
    382 		  if (cu->address_size == 4)
    383 		    address = read_4ubyte_unaligned_inc (dbg, linep);
    384 		  else
    385 		    address = read_8ubyte_unaligned_inc (dbg, linep);
    386 		  break;
    387 
    388 		case DW_LNE_define_file:
    389 		  {
    390 		    char *fname = (char *) linep;
    391 		    uint8_t *endp = memchr (linep, '\0', lineendp - linep);
    392 		    if (endp == NULL)
    393 		      goto invalid_data;
    394 		    size_t fnamelen = endp - linep;
    395 		    linep = endp + 1;
    396 
    397 		    unsigned int diridx;
    398 		    get_uleb128 (diridx, linep);
    399 		    Dwarf_Word mtime;
    400 		    get_uleb128 (mtime, linep);
    401 		    Dwarf_Word filelength;
    402 		    get_uleb128 (filelength, linep);
    403 
    404 		    struct filelist *new_file =
    405 		      (struct filelist *) alloca (sizeof (*new_file));
    406 		    if (fname[0] == '/')
    407 		      new_file->info.name = fname;
    408 		    else
    409 		      {
    410 			new_file->info.name =
    411 			  libdw_alloc (dbg, char, 1, (dirarray[diridx]->len + 1
    412 						      + fnamelen + 1));
    413 			char *cp = new_file->info.name;
    414 
    415 			if (dirarray[diridx]->dir != NULL)
    416 			  /* This value could be NULL in case the
    417 			     DW_AT_comp_dir was not present.  We
    418 			     cannot do much in this case.  The easiest
    419 			     thing is to convert the path in an
    420 			     absolute path.  */
    421 			  cp = stpcpy (cp, dirarray[diridx]->dir);
    422 			*cp++ = '/';
    423 			strcpy (cp, fname);
    424 		      }
    425 
    426 		    new_file->info.mtime = mtime;
    427 		    new_file->info.length = filelength;
    428 		    new_file->next = filelist;
    429 		    filelist = new_file;
    430 		    ++nfilelist;
    431 		  }
    432 		  break;
    433 
    434 		default:
    435 		  /* Unknown, ignore it.  */
    436 		  linep += len - 1;
    437 		  break;
    438 		}
    439 	    }
    440 	  else if (opcode <= DW_LNS_set_epilog_begin)
    441 	    {
    442 	      /* This is a known standard opcode.  */
    443 	      switch (opcode)
    444 		{
    445 		case DW_LNS_copy:
    446 		  /* Takes no argument.  */
    447 		  if (unlikely (standard_opcode_lengths[opcode] != 0))
    448 		    goto invalid_data;
    449 
    450 		  /* Add a new line with the current state machine values.  */
    451 		  NEW_LINE (0);
    452 
    453 		  /* Reset the flags.  */
    454 		  basic_block = 0;
    455 		  /* XXX Whether the following two lines are necessary is
    456 		     unclear.  I guess the current v2.1 specification has
    457 		     a bug in that it says clearing these two registers is
    458 		     not necessary.  */
    459 		  prologue_end = 0;
    460 		  epilogue_begin = 0;
    461 		  break;
    462 
    463 		case DW_LNS_advance_pc:
    464 		  /* Takes one uleb128 parameter which is added to the
    465 		     address.  */
    466 		  if (unlikely (standard_opcode_lengths[opcode] != 1))
    467 		    goto invalid_data;
    468 
    469 		  get_uleb128 (u128, linep);
    470 		  address += minimum_instr_len * u128;
    471 		  break;
    472 
    473 		case DW_LNS_advance_line:
    474 		  /* Takes one sleb128 parameter which is added to the
    475 		     line.  */
    476 		  if (unlikely (standard_opcode_lengths[opcode] != 1))
    477 		    goto invalid_data;
    478 
    479 		  get_sleb128 (s128, linep);
    480 		  line += s128;
    481 		  break;
    482 
    483 		case DW_LNS_set_file:
    484 		  /* Takes one uleb128 parameter which is stored in file.  */
    485 		  if (unlikely (standard_opcode_lengths[opcode] != 1))
    486 		    goto invalid_data;
    487 
    488 		  get_uleb128 (u128, linep);
    489 		  file = u128;
    490 		  break;
    491 
    492 		case DW_LNS_set_column:
    493 		  /* Takes one uleb128 parameter which is stored in column.  */
    494 		  if (unlikely (standard_opcode_lengths[opcode] != 1))
    495 		    goto invalid_data;
    496 
    497 		  get_uleb128 (u128, linep);
    498 		  column = u128;
    499 		  break;
    500 
    501 		case DW_LNS_negate_stmt:
    502 		  /* Takes no argument.  */
    503 		  if (unlikely (standard_opcode_lengths[opcode] != 0))
    504 		    goto invalid_data;
    505 
    506 		  is_stmt = 1 - is_stmt;
    507 		  break;
    508 
    509 		case DW_LNS_set_basic_block:
    510 		  /* Takes no argument.  */
    511 		  if (unlikely (standard_opcode_lengths[opcode] != 0))
    512 		    goto invalid_data;
    513 
    514 		  basic_block = 1;
    515 		  break;
    516 
    517 		case DW_LNS_const_add_pc:
    518 		  /* Takes no argument.  */
    519 		  if (unlikely (standard_opcode_lengths[opcode] != 0))
    520 		    goto invalid_data;
    521 
    522 		  address += (minimum_instr_len
    523 			      * ((255 - opcode_base) / line_range));
    524 		  break;
    525 
    526 		case DW_LNS_fixed_advance_pc:
    527 		  /* Takes one 16 bit parameter which is added to the
    528 		     address.  */
    529 		  if (unlikely (standard_opcode_lengths[opcode] != 1))
    530 		    goto invalid_data;
    531 
    532 		  address += read_2ubyte_unaligned_inc (dbg, linep);
    533 		  break;
    534 
    535 		case DW_LNS_set_prologue_end:
    536 		  /* Takes no argument.  */
    537 		  if (unlikely (standard_opcode_lengths[opcode] != 0))
    538 		    goto invalid_data;
    539 
    540 		  prologue_end = 1;
    541 		  break;
    542 
    543 		case DW_LNS_set_epilog_begin:
    544 		  /* Takes no argument.  */
    545 		  if (unlikely (standard_opcode_lengths[opcode] != 0))
    546 		    goto invalid_data;
    547 
    548 		  epilogue_begin = 1;
    549 		  break;
    550 		}
    551 	    }
    552 	  else
    553 	    {
    554 	      /* This is a new opcode the generator but not we know about.
    555 		 Read the parameters associated with it but then discard
    556 		 everything.  Read all the parameters for this opcode.  */
    557 	      for (int n = standard_opcode_lengths[opcode]; n > 0; --n)
    558 		get_uleb128 (u128, linep);
    559 
    560 	      /* Next round, ignore this opcode.  */
    561 	      continue;
    562 	    }
    563 	}
    564 
    565       /* Put all the files in an array.  */
    566       Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files,
    567 					sizeof (Dwarf_Files)
    568 					+ nfilelist * sizeof (Dwarf_Fileinfo),
    569 				       1);
    570       files->nfiles = nfilelist;
    571       while (nfilelist-- > 0)
    572 	{
    573 	  files->info[nfilelist] = filelist->info;
    574 	  filelist = filelist->next;
    575 	}
    576       assert (filelist == NULL);
    577 
    578       /* Remember the debugging descriptor.  */
    579       files->dbg = dbg;
    580 
    581       /* Make the file data structure available through the CU.  */
    582       cu->files = files;
    583 
    584       cu->lines = libdw_alloc (dbg, Dwarf_Lines, (sizeof (Dwarf_Lines)
    585 						  + (sizeof (Dwarf_Line)
    586 						     * nlinelist)), 1);
    587       cu->lines->nlines = nlinelist;
    588       while (nlinelist-- > 0)
    589 	{
    590 	  cu->lines->info[nlinelist] = linelist->line;
    591 	  cu->lines->info[nlinelist].files = files;
    592 	  linelist = linelist->next;
    593 	}
    594       assert (linelist == NULL);
    595 
    596       /* Success.  */
    597       res = 0;
    598     }
    599   else if (cu->lines != (void *) -1l)
    600     /* We already have the information.  */
    601     res = 0;
    602 
    603   if (likely (res == 0))
    604     {
    605       *lines = cu->lines;
    606       *nlines = cu->lines->nlines;
    607     }
    608  out:
    609 
    610   // XXX Eventually: unlocking here.
    611 
    612   return res;
    613 }
    614