2 * Copyright (c) 2005-2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
29 #include "debugline.h"
31 struct line_reader_data
35 /* From the line number information header. */
36 uint8_t minimum_instruction_length
;
40 const uint8_t * standard_opcode_lengths
;
42 const uint8_t * * dirnames
;
44 size_t numfile
; /* As updated during execution of the table. */
45 const uint8_t * * filenames
;
47 /* Current position in the line table. */
49 /* End of this part of the line table. */
51 /* Start of the line table. */
57 /* Read in a word of fixed size, which may be unaligned, in the
58 appropriate endianness. */
59 #define read_16(p) (lnd->little_endian \
60 ? ((p)[1] << 8 | (p)[0]) \
61 : ((p)[0] << 8 | (p)[1]))
62 #define read_32(p) (lnd->little_endian \
63 ? ((p)[3] << 24 | (p)[2] << 16 | (p)[1] << 8 | (p)[0]) \
64 : ((p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3]))
65 #define read_64(p) (lnd->little_endian \
66 ? ((uint64_t) (p)[7] << 56 | (uint64_t) (p)[6] << 48 \
67 | (uint64_t) (p)[5] << 40 | (uint64_t) (p)[4] << 32 \
68 | (uint64_t) (p)[3] << 24 | (uint64_t) (p)[2] << 16u \
69 | (uint64_t) (p)[1] << 8 | (uint64_t) (p)[0]) \
70 : ((uint64_t) (p)[0] << 56 | (uint64_t) (p)[1] << 48 \
71 | (uint64_t) (p)[2] << 40 | (uint64_t) (p)[3] << 32 \
72 | (uint64_t) (p)[4] << 24 | (uint64_t) (p)[5] << 16u \
73 | (uint64_t) (p)[6] << 8 | (uint64_t) (p)[7]))
75 /* Skip over a LEB128 value (signed or unsigned). */
77 skip_leb128 (struct line_reader_data
* leb
)
79 while (leb
->cpos
!= leb
->end
&& *leb
->cpos
>= 0x80)
81 if (leb
->cpos
!= leb
->end
)
85 /* Read a ULEB128 into a 64-bit word. Return (uint64_t)-1 on overflow
86 or error. On overflow, skip past the rest of the uleb128. */
88 read_uleb128 (struct line_reader_data
* leb
)
96 if (leb
->cpos
== leb
->end
)
99 b
= *leb
->cpos
& 0x7f;
101 if (bit
>= 64 || b
<< bit
>> bit
!= b
)
102 result
= (uint64_t) -1;
104 result
|= b
<< bit
, bit
+= 7;
105 } while (*leb
->cpos
++ >= 0x80);
110 /* Read a SLEB128 into a 64-bit word. Return 0 on overflow or error
111 (which is not very helpful). On overflow, skip past the rest of
112 the SLEB128. For negative numbers, this actually overflows when
113 under -2^62, but since this is used for line numbers that ought to
116 read_sleb128 (struct line_reader_data
* leb
)
118 const uint8_t * start_pos
= leb
->cpos
;
119 uint64_t v
= read_uleb128 (leb
);
124 if (leb
->cpos
- start_pos
> 9)
127 signbit
= 1ull << ((leb
->cpos
- start_pos
) * 7 - 1);
129 return v
| -(v
& signbit
);
132 /* Free a line_reader_data structure. */
134 line_free (struct line_reader_data
* lnd
)
139 free (lnd
->dirnames
);
141 free (lnd
->filenames
);
145 /* Return the pathname of the file in S, or NULL on error.
146 The result will have been allocated with malloc. */
149 line_file (struct line_reader_data
*lnd
, uint64_t n
)
151 const uint8_t * prev_pos
= lnd
->cpos
;
152 size_t filelen
, dirlen
;
156 /* I'm not sure if this is actually an error. */
161 filelen
= strlen ((const char *)lnd
->filenames
[n
- 1]);
162 lnd
->cpos
= lnd
->filenames
[n
- 1] + filelen
+ 1;
163 dir
= read_uleb128 (lnd
);
164 lnd
->cpos
= prev_pos
;
166 || lnd
->filenames
[n
- 1][0] == '/')
167 return strdup ((const char *)lnd
->filenames
[n
- 1]);
168 else if (dir
> lnd
->numdir
)
171 dirlen
= strlen ((const char *) lnd
->dirnames
[dir
- 1]);
172 result
= malloc (dirlen
+ filelen
+ 2);
173 memcpy (result
, lnd
->dirnames
[dir
- 1], dirlen
);
174 result
[dirlen
] = '/';
175 memcpy (result
+ dirlen
+ 1, lnd
->filenames
[n
- 1], filelen
);
176 result
[dirlen
+ 1 + filelen
] = '\0';
180 /* Initialize a state S. Return FALSE on error. */
183 init_state (struct line_info
*s
)
189 s
->end_of_sequence
= false;
192 /* Read a debug_line section. */
194 struct line_reader_data
*
195 line_open (const uint8_t * debug_line
, size_t debug_line_size
,
198 struct line_reader_data
* lnd
= NULL
;
201 uint64_t lnd_length
, header_length
;
202 const uint8_t * table_start
;
204 if (debug_line_size
< 12)
207 lnd
= malloc (sizeof (struct line_reader_data
));
210 bzero(lnd
, sizeof(struct line_reader_data
));
212 lnd
->little_endian
= little_endian
;
213 lnd
->cpos
= debug_line
;
215 lnd_length
= read_32 (lnd
->cpos
);
217 if (lnd_length
== 0xffffffff)
219 lnd_length
= read_64 (lnd
->cpos
);
221 dwarf_size_64
= true;
223 else if (lnd_length
> 0xfffffff0)
224 /* Not a format we understand. */
227 dwarf_size_64
= false;
229 if (debug_line_size
< lnd_length
+ (dwarf_size_64
? 12 : 4)
230 || lnd_length
< (dwarf_size_64
? 15 : 11))
234 if (read_16 (lnd
->cpos
) != 2)
235 /* Unknown line number format. */
239 header_length
= dwarf_size_64
? (uint64_t)read_64(lnd
->cpos
) : (uint64_t)read_32(lnd
->cpos
);
240 lnd
->cpos
+= dwarf_size_64
? 8 : 4;
241 if (lnd_length
< header_length
+ (lnd
->cpos
- debug_line
)
242 || header_length
< 7)
245 lnd
->minimum_instruction_length
= lnd
->cpos
[0];
246 /* Ignore default_is_stmt. */
247 lnd
->line_base
= lnd
->cpos
[2];
248 lnd
->line_range
= lnd
->cpos
[3];
249 lnd
->opcode_base
= lnd
->cpos
[4];
251 if (lnd
->opcode_base
== 0)
252 /* Every valid line number program must use at least opcode 0
253 for DW_LNE_end_sequence. */
256 lnd
->standard_opcode_lengths
= lnd
->cpos
+ 5;
257 if (header_length
< (uint64_t)(5 + (lnd
->opcode_base
- 1)))
258 /* Header not long enough. */
260 lnd
->cpos
+= 5 + lnd
->opcode_base
- 1;
261 lnd
->end
= debug_line
+ header_length
+ (dwarf_size_64
? 22 : 10);
263 /* Make table of offsets to directory names. */
264 table_start
= lnd
->cpos
;
266 while (lnd
->cpos
!= lnd
->end
&& *lnd
->cpos
)
268 lnd
->cpos
= memchr (lnd
->cpos
, 0, lnd
->end
- lnd
->cpos
);
274 if (lnd
->cpos
== lnd
->end
)
276 lnd
->dirnames
= malloc (lnd
->numdir
* sizeof (const uint8_t *));
280 lnd
->cpos
= table_start
;
283 lnd
->dirnames
[lnd
->numdir
++] = lnd
->cpos
;
284 lnd
->cpos
= memchr (lnd
->cpos
, 0, lnd
->end
- lnd
->cpos
) + 1;
288 /* Make table of offsets to file entries. */
289 table_start
= lnd
->cpos
;
291 while (lnd
->cpos
!= lnd
->end
&& *lnd
->cpos
)
293 lnd
->cpos
= memchr (lnd
->cpos
, 0, lnd
->end
- lnd
->cpos
);
302 if (lnd
->cpos
== lnd
->end
)
304 lnd
->filenames
= malloc (lnd
->numfile
* sizeof (const uint8_t *));
305 if (! lnd
->filenames
)
308 lnd
->cpos
= table_start
;
311 lnd
->filenames
[lnd
->numfile
++] = lnd
->cpos
;
312 lnd
->cpos
= memchr (lnd
->cpos
, 0, lnd
->end
- lnd
->cpos
) + 1;
319 lnd
->numfile_orig
= lnd
->numfile
;
320 lnd
->cpos
= lnd
->init
= lnd
->end
;
321 lnd
->end
= debug_line
+ lnd_length
+ (dwarf_size_64
? 12 : 4);
323 init_state (&lnd
->cur
);
332 /* Reset back to the beginning. */
334 line_reset (struct line_reader_data
* lnd
)
336 lnd
->cpos
= lnd
->init
;
337 lnd
->numfile
= lnd
->numfile_orig
;
338 init_state (&lnd
->cur
);
341 /* Is there no more line data available? */
343 line_at_eof (struct line_reader_data
* lnd
)
345 return lnd
->cpos
== lnd
->end
;
348 static const bool verbose
= false;
351 next_state (struct line_reader_data
*lnd
)
353 if (lnd
->cur
.end_of_sequence
)
354 init_state (&lnd
->cur
);
361 if (lnd
->cpos
== lnd
->end
)
364 if (op
>= lnd
->opcode_base
)
366 op
-= lnd
->opcode_base
;
368 lnd
->cur
.line
+= op
% lnd
->line_range
+ lnd
->line_base
;
369 lnd
->cur
.pc
+= (op
/ lnd
->line_range
370 * lnd
->minimum_instruction_length
);
375 case DW_LNS_extended_op
:
377 uint64_t sz
= read_uleb128 (lnd
);
378 const uint8_t * eop
= lnd
->cpos
;
380 if ((uint64_t)(lnd
->end
- eop
) < sz
|| sz
== 0)
385 case DW_LNE_end_sequence
:
386 if (verbose
) fprintf(stderr
, "DW_LNE_end_sequence\n");
387 lnd
->cur
.end_of_sequence
= true;
390 case DW_LNE_set_address
:
392 lnd
->cur
.pc
= read_64 (eop
);
393 if (verbose
) fprintf(stderr
, "DW_LNE_set_address(0x%08llX)\n", lnd
->cur
.pc
);
396 lnd
->cur
.pc
= read_32 (eop
);
397 if (verbose
) fprintf(stderr
, "DW_LNE_set_address(0x%08llX)\n", lnd
->cur
.pc
);
403 case DW_LNE_define_file
:
405 if (verbose
) fprintf(stderr
, "DW_LNE_define_file\n");
406 const uint8_t * * filenames
;
409 (lnd
->numfile
+ 1) * sizeof (const uint8_t *));
412 /* Check for zero-termination. */
413 if (! memchr (eop
, 0, lnd
->cpos
- eop
))
415 filenames
[lnd
->numfile
++] = eop
;
416 lnd
->filenames
= filenames
;
418 /* There's other data here, like file sizes and modification
419 times, but we don't need to read it so skip it. */
424 /* Don't understand it, so skip it. */
425 if (verbose
) fprintf(stderr
, "DW_LNS_extended_op unknown\n");
432 if (verbose
) fprintf(stderr
, "DW_LNS_copy\n");
434 case DW_LNS_advance_pc
:
435 tmp
= read_uleb128 (lnd
);
436 if (tmp
== (uint64_t) -1)
438 lnd
->cur
.pc
+= tmp
* lnd
->minimum_instruction_length
;
439 if (verbose
) fprintf(stderr
, "DW_LNS_advance_pc(0x%08llX)\n", lnd
->cur
.pc
);
441 case DW_LNS_advance_line
:
442 lnd
->cur
.line
+= read_sleb128 (lnd
);
443 if (verbose
) fprintf(stderr
, "DW_LNS_advance_line(%lld)\n", lnd
->cur
.line
);
445 case DW_LNS_set_file
:
446 if (verbose
) fprintf(stderr
, "DW_LNS_set_file\n");
447 lnd
->cur
.file
= read_uleb128 (lnd
);
449 case DW_LNS_set_column
:
450 if (verbose
) fprintf(stderr
, "DW_LNS_set_column\n");
451 lnd
->cur
.col
= read_uleb128 (lnd
);
453 case DW_LNS_const_add_pc
:
454 if (verbose
) fprintf(stderr
, "DW_LNS_const_add_pc\n");
455 lnd
->cur
.pc
+= ((255 - lnd
->opcode_base
) / lnd
->line_range
456 * lnd
->minimum_instruction_length
);
458 case DW_LNS_fixed_advance_pc
:
459 if (verbose
) fprintf(stderr
, "DW_LNS_fixed_advance_pc\n");
460 if (lnd
->end
- lnd
->cpos
< 2)
462 lnd
->cur
.pc
+= read_16 (lnd
->cpos
);
467 /* Don't know what it is, so skip it. */
468 if (verbose
) fprintf(stderr
, "unknown opcode\n");
470 for (i
= 0; i
< lnd
->standard_opcode_lengths
[op
- 1]; i
++)
479 /* Set RESULT to the next 'interesting' line state, as indicated
480 by STOP, or return FALSE on error. The final (end-of-sequence)
481 line state is always considered interesting. */
483 line_next (struct line_reader_data
* lnd
,
484 struct line_info
* result
,
485 enum line_stop_constants stop
)
489 struct line_info prev
= lnd
->cur
;
491 if (! next_state (lnd
))
494 if (lnd
->cur
.end_of_sequence
)
496 if (stop
== line_stop_always
)
498 if ((stop
& line_stop_pc
) && lnd
->cur
.pc
!= prev
.pc
)
500 if ((stop
& line_stop_pos_mask
) && lnd
->cur
.file
!= prev
.file
)
502 if ((stop
& line_stop_pos_mask
) >= line_stop_line
503 && lnd
->cur
.line
!= prev
.line
)
505 if ((stop
& line_stop_pos_mask
) >= line_stop_col
506 && lnd
->cur
.col
!= prev
.col
)
513 /* Find the region (START->pc through END->pc) in the debug_line
514 information which contains PC. This routine starts searching at
515 the current position (which is returned as END), and will go all
516 the way around the debug_line information. It will return false if
517 an error occurs or if there is no matching region; these may be
518 distinguished by looking at START->end_of_sequence, which will be
519 false on error and true if there was no matching region.
520 You could write this routine using line_next, but this version
521 will be slightly more efficient, and of course more convenient. */
524 line_find_addr (struct line_reader_data
* lnd
,
525 struct line_info
* start
,
526 struct line_info
* end
,
529 const uint8_t * startpos
;
530 struct line_info prev
;
532 if (lnd
->cur
.end_of_sequence
&& lnd
->cpos
== lnd
->end
)
535 startpos
= lnd
->cpos
;
539 if (! next_state (lnd
))
541 start
->end_of_sequence
= false;
544 if (lnd
->cur
.end_of_sequence
&& lnd
->cpos
== lnd
->end
)
546 if (lnd
->cpos
== startpos
)
548 start
->end_of_sequence
= true;
551 } while (lnd
->cur
.pc
<= pc
|| prev
.pc
> pc
|| prev
.end_of_sequence
);