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
;
155 const char * dirpath
;
157 /* I'm not sure if this is actually an error. */
162 filelen
= strlen ((const char *)lnd
->filenames
[n
- 1]);
163 lnd
->cpos
= lnd
->filenames
[n
- 1] + filelen
+ 1;
164 dir
= read_uleb128 (lnd
);
165 lnd
->cpos
= prev_pos
;
167 || lnd
->filenames
[n
- 1][0] == '/')
168 return strdup ((const char *)lnd
->filenames
[n
- 1]);
169 else if (dir
> lnd
->numdir
)
172 dirpath
= (const char *)lnd
->dirnames
[dir
- 1];
173 dirlen
= strlen (dirpath
);
174 if ( dirpath
[dirlen
-1] == '/' )
176 if ( (dirpath
[dirlen
-1] == '.') && (dirpath
[dirlen
-2] == '/') )
178 result
= malloc (dirlen
+ filelen
+ 2);
179 memcpy (result
, dirpath
, dirlen
);
180 result
[dirlen
] = '/';
181 memcpy (result
+ dirlen
+ 1, lnd
->filenames
[n
- 1], filelen
);
182 result
[dirlen
+ 1 + filelen
] = '\0';
186 /* Initialize a state S. Return FALSE on error. */
189 init_state (struct line_info
*s
)
195 s
->end_of_sequence
= false;
198 /* Read a debug_line section. */
200 struct line_reader_data
*
201 line_open (const uint8_t * debug_line
, size_t debug_line_size
,
204 struct line_reader_data
* lnd
= NULL
;
207 uint64_t lnd_length
, header_length
;
208 const uint8_t * table_start
;
210 if (debug_line_size
< 12)
213 lnd
= malloc (sizeof (struct line_reader_data
));
216 bzero(lnd
, sizeof(struct line_reader_data
));
218 lnd
->little_endian
= little_endian
;
219 lnd
->cpos
= debug_line
;
221 lnd_length
= read_32 (lnd
->cpos
);
223 if (lnd_length
== 0xffffffff)
225 lnd_length
= read_64 (lnd
->cpos
);
227 dwarf_size_64
= true;
229 else if (lnd_length
> 0xfffffff0)
230 /* Not a format we understand. */
233 dwarf_size_64
= false;
235 if (debug_line_size
< lnd_length
+ (dwarf_size_64
? 12 : 4)
236 || lnd_length
< (dwarf_size_64
? 15 : 11))
240 if (read_16 (lnd
->cpos
) != 2)
241 /* Unknown line number format. */
245 header_length
= dwarf_size_64
? (uint64_t)read_64(lnd
->cpos
) : (uint64_t)read_32(lnd
->cpos
);
246 lnd
->cpos
+= dwarf_size_64
? 8 : 4;
247 if (lnd_length
< header_length
+ (lnd
->cpos
- debug_line
)
248 || header_length
< 7)
251 lnd
->minimum_instruction_length
= lnd
->cpos
[0];
252 /* Ignore default_is_stmt. */
253 lnd
->line_base
= lnd
->cpos
[2];
254 lnd
->line_range
= lnd
->cpos
[3];
255 lnd
->opcode_base
= lnd
->cpos
[4];
257 if (lnd
->opcode_base
== 0)
258 /* Every valid line number program must use at least opcode 0
259 for DW_LNE_end_sequence. */
262 lnd
->standard_opcode_lengths
= lnd
->cpos
+ 5;
263 if (header_length
< (uint64_t)(5 + (lnd
->opcode_base
- 1)))
264 /* Header not long enough. */
266 lnd
->cpos
+= 5 + lnd
->opcode_base
- 1;
267 lnd
->end
= debug_line
+ header_length
+ (dwarf_size_64
? 22 : 10);
269 /* Make table of offsets to directory names. */
270 table_start
= lnd
->cpos
;
272 while (lnd
->cpos
!= lnd
->end
&& *lnd
->cpos
)
274 lnd
->cpos
= memchr (lnd
->cpos
, 0, lnd
->end
- lnd
->cpos
);
280 if (lnd
->cpos
== lnd
->end
)
282 lnd
->dirnames
= malloc (lnd
->numdir
* sizeof (const uint8_t *));
286 lnd
->cpos
= table_start
;
289 lnd
->dirnames
[lnd
->numdir
++] = lnd
->cpos
;
290 lnd
->cpos
= memchr (lnd
->cpos
, 0, lnd
->end
- lnd
->cpos
) + 1;
294 /* Make table of offsets to file entries. */
295 table_start
= lnd
->cpos
;
297 while (lnd
->cpos
!= lnd
->end
&& *lnd
->cpos
)
299 lnd
->cpos
= memchr (lnd
->cpos
, 0, lnd
->end
- lnd
->cpos
);
308 if (lnd
->cpos
== lnd
->end
)
310 lnd
->filenames
= malloc (lnd
->numfile
* sizeof (const uint8_t *));
311 if (! lnd
->filenames
)
314 lnd
->cpos
= table_start
;
317 lnd
->filenames
[lnd
->numfile
++] = lnd
->cpos
;
318 lnd
->cpos
= memchr (lnd
->cpos
, 0, lnd
->end
- lnd
->cpos
) + 1;
325 lnd
->numfile_orig
= lnd
->numfile
;
326 lnd
->cpos
= lnd
->init
= lnd
->end
;
327 lnd
->end
= debug_line
+ lnd_length
+ (dwarf_size_64
? 12 : 4);
329 init_state (&lnd
->cur
);
338 /* Reset back to the beginning. */
340 line_reset (struct line_reader_data
* lnd
)
342 lnd
->cpos
= lnd
->init
;
343 lnd
->numfile
= lnd
->numfile_orig
;
344 init_state (&lnd
->cur
);
347 /* Is there no more line data available? */
349 line_at_eof (struct line_reader_data
* lnd
)
351 return lnd
->cpos
== lnd
->end
;
354 static const bool verbose
= false;
357 next_state (struct line_reader_data
*lnd
)
359 if (lnd
->cur
.end_of_sequence
)
360 init_state (&lnd
->cur
);
367 if (lnd
->cpos
== lnd
->end
)
370 if (op
>= lnd
->opcode_base
)
372 op
-= lnd
->opcode_base
;
374 lnd
->cur
.line
+= op
% lnd
->line_range
+ lnd
->line_base
;
375 lnd
->cur
.pc
+= (op
/ lnd
->line_range
376 * lnd
->minimum_instruction_length
);
381 case DW_LNS_extended_op
:
383 uint64_t sz
= read_uleb128 (lnd
);
384 const uint8_t * eop
= lnd
->cpos
;
386 if ((uint64_t)(lnd
->end
- eop
) < sz
|| sz
== 0)
391 case DW_LNE_end_sequence
:
392 if (verbose
) fprintf(stderr
, "DW_LNE_end_sequence\n");
393 lnd
->cur
.end_of_sequence
= true;
396 case DW_LNE_set_address
:
398 lnd
->cur
.pc
= read_64 (eop
);
399 if (verbose
) fprintf(stderr
, "DW_LNE_set_address(0x%08llX)\n", lnd
->cur
.pc
);
402 lnd
->cur
.pc
= read_32 (eop
);
403 if (verbose
) fprintf(stderr
, "DW_LNE_set_address(0x%08llX)\n", lnd
->cur
.pc
);
409 case DW_LNE_define_file
:
411 if (verbose
) fprintf(stderr
, "DW_LNE_define_file\n");
412 const uint8_t * * filenames
;
415 (lnd
->numfile
+ 1) * sizeof (const uint8_t *));
418 /* Check for zero-termination. */
419 if (! memchr (eop
, 0, lnd
->cpos
- eop
))
421 filenames
[lnd
->numfile
++] = eop
;
422 lnd
->filenames
= filenames
;
424 /* There's other data here, like file sizes and modification
425 times, but we don't need to read it so skip it. */
430 /* Don't understand it, so skip it. */
431 if (verbose
) fprintf(stderr
, "DW_LNS_extended_op unknown\n");
438 if (verbose
) fprintf(stderr
, "DW_LNS_copy\n");
440 case DW_LNS_advance_pc
:
441 tmp
= read_uleb128 (lnd
);
442 if (tmp
== (uint64_t) -1)
444 lnd
->cur
.pc
+= tmp
* lnd
->minimum_instruction_length
;
445 if (verbose
) fprintf(stderr
, "DW_LNS_advance_pc(0x%08llX)\n", lnd
->cur
.pc
);
447 case DW_LNS_advance_line
:
448 lnd
->cur
.line
+= read_sleb128 (lnd
);
449 if (verbose
) fprintf(stderr
, "DW_LNS_advance_line(%lld)\n", lnd
->cur
.line
);
451 case DW_LNS_set_file
:
452 if (verbose
) fprintf(stderr
, "DW_LNS_set_file\n");
453 lnd
->cur
.file
= read_uleb128 (lnd
);
455 case DW_LNS_set_column
:
456 if (verbose
) fprintf(stderr
, "DW_LNS_set_column\n");
457 lnd
->cur
.col
= read_uleb128 (lnd
);
459 case DW_LNS_const_add_pc
:
460 if (verbose
) fprintf(stderr
, "DW_LNS_const_add_pc\n");
461 lnd
->cur
.pc
+= ((255 - lnd
->opcode_base
) / lnd
->line_range
462 * lnd
->minimum_instruction_length
);
464 case DW_LNS_fixed_advance_pc
:
465 if (verbose
) fprintf(stderr
, "DW_LNS_fixed_advance_pc\n");
466 if (lnd
->end
- lnd
->cpos
< 2)
468 lnd
->cur
.pc
+= read_16 (lnd
->cpos
);
473 /* Don't know what it is, so skip it. */
474 if (verbose
) fprintf(stderr
, "unknown opcode\n");
476 for (i
= 0; i
< lnd
->standard_opcode_lengths
[op
- 1]; i
++)
485 /* Set RESULT to the next 'interesting' line state, as indicated
486 by STOP, or return FALSE on error. The final (end-of-sequence)
487 line state is always considered interesting. */
489 line_next (struct line_reader_data
* lnd
,
490 struct line_info
* result
,
491 enum line_stop_constants stop
)
495 struct line_info prev
= lnd
->cur
;
497 if (! next_state (lnd
))
500 if (lnd
->cur
.end_of_sequence
)
502 if (stop
== line_stop_always
)
504 if ((stop
& line_stop_pc
) && lnd
->cur
.pc
!= prev
.pc
)
506 if ((stop
& line_stop_pos_mask
) && lnd
->cur
.file
!= prev
.file
)
508 if ((stop
& line_stop_pos_mask
) >= line_stop_line
509 && lnd
->cur
.line
!= prev
.line
)
511 if ((stop
& line_stop_pos_mask
) >= line_stop_col
512 && lnd
->cur
.col
!= prev
.col
)
519 /* Find the region (START->pc through END->pc) in the debug_line
520 information which contains PC. This routine starts searching at
521 the current position (which is returned as END), and will go all
522 the way around the debug_line information. It will return false if
523 an error occurs or if there is no matching region; these may be
524 distinguished by looking at START->end_of_sequence, which will be
525 false on error and true if there was no matching region.
526 You could write this routine using line_next, but this version
527 will be slightly more efficient, and of course more convenient. */
530 line_find_addr (struct line_reader_data
* lnd
,
531 struct line_info
* start
,
532 struct line_info
* end
,
535 const uint8_t * startpos
;
536 struct line_info prev
;
538 if (lnd
->cur
.end_of_sequence
&& lnd
->cpos
== lnd
->end
)
541 startpos
= lnd
->cpos
;
545 if (! next_state (lnd
))
547 start
->end_of_sequence
= false;
550 if (lnd
->cur
.end_of_sequence
&& lnd
->cpos
== lnd
->end
)
552 if (lnd
->cpos
== startpos
)
554 start
->end_of_sequence
= true;
557 } while (lnd
->cur
.pc
<= pc
|| prev
.pc
> pc
|| prev
.end_of_sequence
);