• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Return line number information of CU.
2    Copyright (C) 2004 Red Hat, Inc.
3    Written by Ulrich Drepper <drepper@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
dwarf_getsrclines(Dwarf_Die * cudie,Dwarf_Lines ** lines,size_t * nlines)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