X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=binutils%2Fdwarf.c;h=387504fc6303b1f17c872b4d06380fcd02f01c8c;hb=2e877f5ecb5916d147f91dfad461a8fa5017d8b0;hp=8a55aeb7e7b2483a064f9d3e63dd3823e3fb3d4f;hpb=341f9135d1885938b00198811b1a81bfc3c726fd;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 8a55aeb7e7..387504fc63 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -1,6 +1,5 @@ /* dwarf.c -- display DWARF contents of a BFD binary file - Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 - Free Software Foundation, Inc. + Copyright 2005-2013 Free Software Foundation, Inc. This file is part of GNU Binutils. @@ -30,6 +29,10 @@ #include "dwarf.h" #include "gdb/gdb-index.h" +#if !HAVE_DECL_STRNLEN +size_t strnlen (const char *, size_t); +#endif + static const char *regname (unsigned int regno, int row); static int have_frame_base; @@ -136,52 +139,27 @@ get_encoded_value (unsigned char *data, return val; } -/* Print a dwarf_vma value (typically an address, offset or length) in - hexadecimal format, followed by a space. The length of the value (and - hence the precision displayed) is determined by the byte_size parameter. */ - -static void -print_dwarf_vma (dwarf_vma val, unsigned byte_size) -{ - static char buff[18]; - int offset = 0; - - /* Printf does not have a way of specifiying a maximum field width for an - integer value, so we print the full value into a buffer and then select - the precision we need. */ #if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2) #ifndef __MINGW32__ - snprintf (buff, sizeof (buff), "%16.16llx ", val); +#define DWARF_VMA_FMT "ll" +#define DWARF_VMA_FMT_LONG "%16.16llx" #else - snprintf (buff, sizeof (buff), "%016I64x ", val); +#define DWARF_VMA_FMT "I64" +#define DWARF_VMA_FMT_LONG "%016I64x" #endif #else - snprintf (buff, sizeof (buff), "%16.16lx ", val); +#define DWARF_VMA_FMT "l" +#define DWARF_VMA_FMT_LONG "%16.16lx" #endif - if (byte_size != 0) - { - if (byte_size > 0 && byte_size <= 8) - offset = 16 - 2 * byte_size; - else - error (_("Wrong size in print_dwarf_vma")); - } - - fputs (buff + offset, stdout); -} - -#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2) -#ifndef __MINGW32__ -#define DWARF_VMA_FMT "ll" -#else -#define DWARF_VMA_FMT "I64" -#endif -#else -#define DWARF_VMA_FMT "l" -#endif +/* Convert a dwarf vma value into a string. Returns a pointer to a static + buffer containing the converted VALUE. The value is converted according + to the printf formating character FMTCH. If NUM_BYTES is non-zero then + it specifies the maximum number of bytes to be displayed in the converted + value and FMTCH is ignored - hex is always used. */ static const char * -dwarf_vmatoa (const char *fmtch, dwarf_vma value) +dwarf_vmatoa_1 (const char *fmtch, dwarf_vma value, unsigned num_bytes) { /* As dwarf_vmatoa is used more then once in a printf call for output, we are cycling through an fixed array of pointers @@ -191,17 +169,45 @@ dwarf_vmatoa (const char *fmtch, dwarf_vma value) { char place[64]; } buf[16]; - char fmt[32]; char *ret; - sprintf (fmt, "%%%s%s", DWARF_VMA_FMT, fmtch); - ret = buf[buf_pos++].place; buf_pos %= ARRAY_SIZE (buf); - snprintf (ret, sizeof (buf[0].place), fmt, value); + if (num_bytes) + { + /* Printf does not have a way of specifiying a maximum field width for an + integer value, so we print the full value into a buffer and then select + the precision we need. */ + snprintf (ret, sizeof (buf[0].place), DWARF_VMA_FMT_LONG, value); + if (num_bytes > 8) + num_bytes = 8; + return ret + (16 - 2 * num_bytes); + } + else + { + char fmt[32]; - return ret; + sprintf (fmt, "%%%s%s", DWARF_VMA_FMT, fmtch); + snprintf (ret, sizeof (buf[0].place), fmt, value); + return ret; + } +} + +static inline const char * +dwarf_vmatoa (const char * fmtch, dwarf_vma value) +{ + return dwarf_vmatoa_1 (fmtch, value, 0); +} + +/* Print a dwarf_vma value (typically an address, offset or length) in + hexadecimal format, followed by a space. The length of the VALUE (and + hence the precision displayed) is determined by the NUM_BYTES parameter. */ + +static void +print_dwarf_vma (dwarf_vma value, unsigned num_bytes) +{ + printf ("%s ", dwarf_vmatoa_1 (NULL, value, num_bytes)); } /* Format a 64-bit value, given as two 32-bit values, in hex. @@ -225,15 +231,23 @@ dwarf_vmatoa64 (dwarf_vma hvalue, dwarf_vma lvalue, char *buf, return buf; } +/* Read in a LEB128 encoded value starting at address DATA. + If SIGN is true, return a signed LEB128 value. + If LENGTH_RETURN is not NULL, return in it the number of bytes read. + No bytes will be read at address END or beyond. */ + dwarf_vma -read_leb128 (unsigned char *data, unsigned int *length_return, int sign) +read_leb128 (unsigned char *data, + unsigned int *length_return, + bfd_boolean sign, + const unsigned char * const end) { dwarf_vma result = 0; unsigned int num_read = 0; unsigned int shift = 0; - unsigned char byte; + unsigned char byte = 0; - do + while (data < end) { byte = *data++; num_read++; @@ -241,9 +255,9 @@ read_leb128 (unsigned char *data, unsigned int *length_return, int sign) result |= ((dwarf_vma) (byte & 0x7f)) << shift; shift += 7; - + if ((byte & 0x80) == 0) + break; } - while (byte & 0x80); if (length_return != NULL) *length_return = num_read; @@ -255,12 +269,89 @@ read_leb128 (unsigned char *data, unsigned int *length_return, int sign) } /* Create a signed version to avoid painful typecasts. */ -static dwarf_signed_vma -read_sleb128 (unsigned char *data, unsigned int *length_return) +static inline dwarf_signed_vma +read_sleb128 (unsigned char * data, + unsigned int * length_return, + const unsigned char * const end) +{ + return (dwarf_signed_vma) read_leb128 (data, length_return, TRUE, end); +} + +static inline dwarf_vma +read_uleb128 (unsigned char * data, + unsigned int * length_return, + const unsigned char * const end) { - return (dwarf_signed_vma) read_leb128 (data, length_return, 1); + return read_leb128 (data, length_return, FALSE, end); } +#define SAFE_BYTE_GET(VAL, PTR, AMOUNT, END) \ + do \ + { \ + int dummy [sizeof (VAL) < (AMOUNT) ? -1 : 1] ATTRIBUTE_UNUSED ; \ + unsigned int amount = (AMOUNT); \ + if (((PTR) + amount) >= (END)) \ + { \ + if ((PTR) < (END)) \ + amount = (END) - (PTR); \ + else \ + amount = 0; \ + } \ + if (amount) \ + VAL = byte_get ((PTR), amount); \ + else \ + VAL = 0; \ + } \ + while (0) + +#define SAFE_BYTE_GET_AND_INC(VAL, PTR, AMOUNT, END) \ + do \ + { \ + SAFE_BYTE_GET (VAL, PTR, AMOUNT, END); \ + PTR += AMOUNT; \ + } \ + while (0) + +#define SAFE_SIGNED_BYTE_GET(VAL, PTR, AMOUNT, END) \ + do \ + { \ + unsigned int amount = (AMOUNT); \ + if (((PTR) + amount) >= (END)) \ + { \ + if ((PTR) < (END)) \ + amount = (END) - (PTR); \ + else \ + amount = 0; \ + } \ + if (amount) \ + VAL = byte_get_signed ((PTR), amount); \ + else \ + VAL = 0; \ + } \ + while (0) + +#define SAFE_SIGNED_BYTE_GET_AND_INC(VAL, PTR, AMOUNT, END) \ + do \ + { \ + SAFE_SIGNED_BYTE_GET (VAL, PTR, AMOUNT, END); \ + PTR += AMOUNT; \ + } \ + while (0) + +#define SAFE_BYTE_GET64(PTR, HIGH, LOW, END) \ + do \ + { \ + if (((PTR) + 8) <= (END)) \ + { \ + byte_get_64 ((PTR), (HIGH), (LOW)); \ + } \ + else \ + { \ + * (LOW) = * (HIGH) = 0; \ + } \ + } \ + while (0) + typedef struct State_Machine_Registers { dwarf_vma address; @@ -296,19 +387,21 @@ reset_state_machine (int is_stmt) Returns the number of bytes read. */ static int -process_extended_line_op (unsigned char *data, int is_stmt) +process_extended_line_op (unsigned char * data, + int is_stmt, + unsigned char * end) { unsigned char op_code; unsigned int bytes_read; unsigned int len; unsigned char *name; - dwarf_vma adr; unsigned char *orig_data = data; + dwarf_vma adr; - len = read_leb128 (data, & bytes_read, 0); + len = read_uleb128 (data, & bytes_read, end); data += bytes_read; - if (len == 0) + if (len == 0 || data == end) { warn (_("badly formed extended line op encountered!\n")); return bytes_read; @@ -327,7 +420,7 @@ process_extended_line_op (unsigned char *data, int is_stmt) break; case DW_LNE_set_address: - adr = byte_get (data, len - bytes_read - 1); + SAFE_BYTE_GET (adr, data, len - bytes_read - 1, end); printf (_("set Address to 0x%s\n"), dwarf_vmatoa ("x", adr)); state_machine_regs.address = adr; state_machine_regs.op_index = 0; @@ -336,25 +429,25 @@ process_extended_line_op (unsigned char *data, int is_stmt) case DW_LNE_define_file: printf (_("define new File Table entry\n")); printf (_(" Entry\tDir\tTime\tSize\tName\n")); - printf (" %d\t", ++state_machine_regs.last_file_entry); + name = data; - data += strlen ((char *) data) + 1; - printf ("%s\t", dwarf_vmatoa ("u", read_leb128 (data, & bytes_read, 0))); + data += strnlen ((char *) data, end - data) + 1; + printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); data += bytes_read; - printf ("%s\t", dwarf_vmatoa ("u", read_leb128 (data, & bytes_read, 0))); + printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); data += bytes_read; - printf ("%s\t", dwarf_vmatoa ("u", read_leb128 (data, & bytes_read, 0))); + printf ("%s\t", dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); data += bytes_read; - printf ("%s", name); - if ((unsigned int) (data - orig_data) != len) - printf (_(" [Bad opcode length]")); - printf ("\n\n"); + printf ("%s\n\n", name); + + if (((unsigned int) (data - orig_data) != len) || data == end) + warn (_("DW_LNE_define_file: Bad opcode length\n")); break; case DW_LNE_set_discriminator: printf (_("set Discriminator to %s\n"), - dwarf_vmatoa ("u", read_leb128 (data, & bytes_read, 0))); + dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); break; /* HP extensions. */ @@ -398,7 +491,7 @@ process_extended_line_op (unsigned char *data, int is_stmt) { unsigned int opc; - opc = read_leb128 (data, & bytes_read, 0); + opc = read_uleb128 (data, & bytes_read, edata); data += bytes_read; switch (opc) @@ -409,22 +502,22 @@ process_extended_line_op (unsigned char *data, int is_stmt) case DW_LNE_HP_SFC_set_listing_line: printf (" DW_LNE_HP_SFC_set_listing_line (%s)\n", dwarf_vmatoa ("u", - read_leb128 (data, & bytes_read, 0))); + read_uleb128 (data, & bytes_read, edata))); data += bytes_read; break; case DW_LNE_HP_SFC_associate: printf (" DW_LNE_HP_SFC_associate "); printf ("(%s", dwarf_vmatoa ("u", - read_leb128 (data, & bytes_read, 0))); + read_uleb128 (data, & bytes_read, edata))); data += bytes_read; printf (",%s", dwarf_vmatoa ("u", - read_leb128 (data, & bytes_read, 0))); + read_uleb128 (data, & bytes_read, edata))); data += bytes_read; printf (",%s)\n", dwarf_vmatoa ("u", - read_leb128 (data, & bytes_read, 0))); + read_uleb128 (data, & bytes_read, edata))); data += bytes_read; break; default: @@ -459,24 +552,22 @@ process_extended_line_op (unsigned char *data, int is_stmt) return len; } -static const char * +static const unsigned char * fetch_indirect_string (dwarf_vma offset) { struct dwarf_section *section = &debug_displays [str].section; if (section->start == NULL) - return _(""); + return (const unsigned char *) _(""); - /* DWARF sections under Mach-O have non-zero addresses. */ - offset -= section->address; if (offset > section->size) { warn (_("DW_FORM_strp offset too big: %s\n"), dwarf_vmatoa ("x", offset)); - return _(""); + return (const unsigned char *) _(""); } - return (const char *) section->start + offset; + return (const unsigned char *) section->start + offset; } static const char * @@ -494,8 +585,6 @@ fetch_indexed_string (dwarf_vma idx, struct cu_tu_set *this_set, return (dwo ? _("") : _("")); - /* DWARF sections under Mach-O have non-zero addresses. */ - index_offset -= index_section->address; if (this_set != NULL) index_offset += this_set->section_offsets [DW_SECT_STR_OFFSETS]; if (index_offset > index_section->size) @@ -656,17 +745,21 @@ process_abbrev_section (unsigned char *start, unsigned char *end) unsigned long attribute; int children; - entry = read_leb128 (start, & bytes_read, 0); + entry = read_uleb128 (start, & bytes_read, end); start += bytes_read; /* A single zero is supposed to end the section according to the standard. If there's more, then signal that to the caller. */ + if (start == end) + return NULL; if (entry == 0) - return start == end ? NULL : start; + return start; - tag = read_leb128 (start, & bytes_read, 0); + tag = read_uleb128 (start, & bytes_read, end); start += bytes_read; + if (start == end) + return NULL; children = *start++; @@ -676,11 +769,15 @@ process_abbrev_section (unsigned char *start, unsigned char *end) { unsigned long form; - attribute = read_leb128 (start, & bytes_read, 0); + attribute = read_uleb128 (start, & bytes_read, end); start += bytes_read; + if (start == end) + break; - form = read_leb128 (start, & bytes_read, 0); + form = read_uleb128 (start, & bytes_read, end); start += bytes_read; + if (start == end) + break; add_abbrev_attr (attribute, form); } @@ -713,7 +810,7 @@ static const char * get_FORM_name (unsigned long form) { const char *name; - + if (form == 0) return "DW_FORM value: 0"; @@ -730,10 +827,17 @@ get_FORM_name (unsigned long form) } static unsigned char * -display_block (unsigned char *data, dwarf_vma length) +display_block (unsigned char *data, + dwarf_vma length, + const unsigned char * const end) { + dwarf_vma maxlen; + printf (_(" %s byte block: "), dwarf_vmatoa ("u", length)); + maxlen = (dwarf_vma) (end - data); + length = length > maxlen ? maxlen : length; + while (length --) printf ("%lx ", (unsigned long) byte_get (data++, 1)); @@ -752,6 +856,7 @@ decode_location_expression (unsigned char * data, unsigned op; unsigned int bytes_read; dwarf_vma uvalue; + dwarf_signed_vma svalue; unsigned char *end = data + length; int need_frame_base = 0; @@ -762,53 +867,56 @@ decode_location_expression (unsigned char * data, switch (op) { case DW_OP_addr: - printf ("DW_OP_addr: %s", - dwarf_vmatoa ("x", byte_get (data, pointer_size))); - data += pointer_size; + SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end); + printf ("DW_OP_addr: %s", dwarf_vmatoa ("x", uvalue)); break; case DW_OP_deref: printf ("DW_OP_deref"); break; case DW_OP_const1u: - printf ("DW_OP_const1u: %lu", (unsigned long) byte_get (data++, 1)); + SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end); + printf ("DW_OP_const1u: %lu", (unsigned long) uvalue); break; case DW_OP_const1s: - printf ("DW_OP_const1s: %ld", (long) byte_get_signed (data++, 1)); + SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 1, end); + printf ("DW_OP_const1s: %ld", (long) svalue); break; case DW_OP_const2u: - printf ("DW_OP_const2u: %lu", (unsigned long) byte_get (data, 2)); - data += 2; + SAFE_BYTE_GET_AND_INC (uvalue, data, 2, end); + printf ("DW_OP_const2u: %lu", (unsigned long) uvalue); break; case DW_OP_const2s: - printf ("DW_OP_const2s: %ld", (long) byte_get_signed (data, 2)); - data += 2; + SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end); + printf ("DW_OP_const2s: %ld", (long) svalue); break; case DW_OP_const4u: - printf ("DW_OP_const4u: %lu", (unsigned long) byte_get (data, 4)); - data += 4; + SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end); + printf ("DW_OP_const4u: %lu", (unsigned long) uvalue); break; case DW_OP_const4s: - printf ("DW_OP_const4s: %ld", (long) byte_get_signed (data, 4)); - data += 4; + SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end); + printf ("DW_OP_const4s: %ld", (long) svalue); break; case DW_OP_const8u: - printf ("DW_OP_const8u: %lu %lu", (unsigned long) byte_get (data, 4), - (unsigned long) byte_get (data + 4, 4)); - data += 8; + SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end); + printf ("DW_OP_const8u: %lu ", (unsigned long) uvalue); + SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end); + printf ("%lu", (unsigned long) uvalue); break; case DW_OP_const8s: - printf ("DW_OP_const8s: %ld %ld", (long) byte_get (data, 4), - (long) byte_get (data + 4, 4)); - data += 8; + SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end); + printf ("DW_OP_const8s: %ld ", (long) svalue); + SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end); + printf ("%ld", (long) svalue); break; case DW_OP_constu: printf ("DW_OP_constu: %s", - dwarf_vmatoa ("u", read_leb128 (data, &bytes_read, 0))); + dwarf_vmatoa ("u", read_uleb128 (data, &bytes_read, end))); data += bytes_read; break; case DW_OP_consts: printf ("DW_OP_consts: %s", - dwarf_vmatoa ("d", read_sleb128 (data, &bytes_read))); + dwarf_vmatoa ("d", read_sleb128 (data, &bytes_read, end))); data += bytes_read; break; case DW_OP_dup: @@ -821,7 +929,8 @@ decode_location_expression (unsigned char * data, printf ("DW_OP_over"); break; case DW_OP_pick: - printf ("DW_OP_pick: %ld", (unsigned long) byte_get (data++, 1)); + SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end); + printf ("DW_OP_pick: %ld", (unsigned long) uvalue); break; case DW_OP_swap: printf ("DW_OP_swap"); @@ -864,7 +973,7 @@ decode_location_expression (unsigned char * data, break; case DW_OP_plus_uconst: printf ("DW_OP_plus_uconst: %s", - dwarf_vmatoa ("u", read_leb128 (data, &bytes_read, 0))); + dwarf_vmatoa ("u", read_uleb128 (data, &bytes_read, end))); data += bytes_read; break; case DW_OP_shl: @@ -880,8 +989,8 @@ decode_location_expression (unsigned char * data, printf ("DW_OP_xor"); break; case DW_OP_bra: - printf ("DW_OP_bra: %ld", (long) byte_get_signed (data, 2)); - data += 2; + SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end); + printf ("DW_OP_bra: %ld", (long) svalue); break; case DW_OP_eq: printf ("DW_OP_eq"); @@ -902,8 +1011,8 @@ decode_location_expression (unsigned char * data, printf ("DW_OP_ne"); break; case DW_OP_skip: - printf ("DW_OP_skip: %ld", (long) byte_get_signed (data, 2)); - data += 2; + SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end); + printf ("DW_OP_skip: %ld", (long) svalue); break; case DW_OP_lit0: @@ -1012,13 +1121,12 @@ decode_location_expression (unsigned char * data, printf ("DW_OP_breg%d (%s): %s", op - DW_OP_breg0, regname (op - DW_OP_breg0, 1), - dwarf_vmatoa ("d", (dwarf_signed_vma) - read_leb128 (data, &bytes_read, 1))); + dwarf_vmatoa ("d", read_sleb128 (data, &bytes_read, end))); data += bytes_read; break; case DW_OP_regx: - uvalue = read_leb128 (data, &bytes_read, 0); + uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; printf ("DW_OP_regx: %s (%s)", dwarf_vmatoa ("u", uvalue), regname (uvalue, 1)); @@ -1026,27 +1134,29 @@ decode_location_expression (unsigned char * data, case DW_OP_fbreg: need_frame_base = 1; printf ("DW_OP_fbreg: %s", - dwarf_vmatoa ("d", read_sleb128 (data, &bytes_read))); + dwarf_vmatoa ("d", read_sleb128 (data, &bytes_read, end))); data += bytes_read; break; case DW_OP_bregx: - uvalue = read_leb128 (data, &bytes_read, 0); + uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; printf ("DW_OP_bregx: %s (%s) %s", dwarf_vmatoa ("u", uvalue), regname (uvalue, 1), - dwarf_vmatoa ("d", read_sleb128 (data, &bytes_read))); + dwarf_vmatoa ("d", read_sleb128 (data, &bytes_read, end))); data += bytes_read; break; case DW_OP_piece: printf ("DW_OP_piece: %s", - dwarf_vmatoa ("u", read_leb128 (data, &bytes_read, 0))); + dwarf_vmatoa ("u", read_uleb128 (data, &bytes_read, end))); data += bytes_read; break; case DW_OP_deref_size: - printf ("DW_OP_deref_size: %ld", (long) byte_get (data++, 1)); + SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end); + printf ("DW_OP_deref_size: %ld", (long) uvalue); break; case DW_OP_xderef_size: - printf ("DW_OP_xderef_size: %ld", (long) byte_get (data++, 1)); + SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end); + printf ("DW_OP_xderef_size: %ld", (long) uvalue); break; case DW_OP_nop: printf ("DW_OP_nop"); @@ -1059,18 +1169,16 @@ decode_location_expression (unsigned char * data, case DW_OP_call2: /* XXX: Strictly speaking for 64-bit DWARF3 files this ought to be an 8-byte wide computation. */ + SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end); printf ("DW_OP_call2: <0x%s>", - dwarf_vmatoa ("x", (dwarf_signed_vma) byte_get (data, 2) - + cu_offset)); - data += 2; + dwarf_vmatoa ("x", svalue + cu_offset)); break; case DW_OP_call4: /* XXX: Strictly speaking for 64-bit DWARF3 files this ought to be an 8-byte wide computation. */ + SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end); printf ("DW_OP_call4: <0x%s>", - dwarf_vmatoa ("x", (dwarf_signed_vma) byte_get (data, 4) - + cu_offset)); - data += 4; + dwarf_vmatoa ("x", svalue + cu_offset)); break; case DW_OP_call_ref: /* XXX: Strictly speaking for 64-bit DWARF3 files @@ -1083,16 +1191,13 @@ decode_location_expression (unsigned char * data, } if (dwarf_version == 2) { - printf ("DW_OP_call_ref: <0x%s>", - dwarf_vmatoa ("x", byte_get (data, pointer_size))); - data += pointer_size; + SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end); } else { - printf ("DW_OP_call_ref: <0x%s>", - dwarf_vmatoa ("x", byte_get (data, offset_size))); - data += offset_size; + SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end); } + printf ("DW_OP_call_ref: <0x%s>", dwarf_vmatoa ("x", uvalue)); break; case DW_OP_form_tls_address: printf ("DW_OP_form_tls_address"); @@ -1103,10 +1208,10 @@ decode_location_expression (unsigned char * data, case DW_OP_bit_piece: printf ("DW_OP_bit_piece: "); printf (_("size: %s "), - dwarf_vmatoa ("u", read_leb128 (data, &bytes_read, 0))); + dwarf_vmatoa ("u", read_uleb128 (data, &bytes_read, end))); data += bytes_read; printf (_("offset: %s "), - dwarf_vmatoa ("u", read_leb128 (data, &bytes_read, 0))); + dwarf_vmatoa ("u", read_uleb128 (data, &bytes_read, end))); data += bytes_read; break; @@ -1117,9 +1222,9 @@ decode_location_expression (unsigned char * data, case DW_OP_implicit_value: printf ("DW_OP_implicit_value"); - uvalue = read_leb128 (data, &bytes_read, 0); + uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; - display_block (data, uvalue); + display_block (data, uvalue, end); data += uvalue; break; @@ -1155,23 +1260,20 @@ decode_location_expression (unsigned char * data, } if (dwarf_version == 2) { - printf ("DW_OP_GNU_implicit_pointer: <0x%s> %s", - dwarf_vmatoa ("x", byte_get (data, pointer_size)), - dwarf_vmatoa ("d", read_sleb128 (data + pointer_size, - &bytes_read))); - data += pointer_size + bytes_read; + SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end); } else { - printf ("DW_OP_GNU_implicit_pointer: <0x%s> %s", - dwarf_vmatoa ("x", byte_get (data, offset_size)), - dwarf_vmatoa ("d", read_sleb128 (data + offset_size, - &bytes_read))); - data += offset_size + bytes_read; + SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end); } + printf ("DW_OP_GNU_implicit_pointer: <0x%s> %s", + dwarf_vmatoa ("x", uvalue), + dwarf_vmatoa ("d", read_sleb128 (data, + &bytes_read, end))); + data += bytes_read; break; case DW_OP_GNU_entry_value: - uvalue = read_leb128 (data, &bytes_read, 0); + uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; printf ("DW_OP_GNU_entry_value: ("); if (decode_location_expression (data, pointer_size, offset_size, @@ -1182,53 +1284,54 @@ decode_location_expression (unsigned char * data, data += uvalue; break; case DW_OP_GNU_const_type: - uvalue = read_leb128 (data, &bytes_read, 0); + uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; printf ("DW_OP_GNU_const_type: <0x%s> ", dwarf_vmatoa ("x", cu_offset + uvalue)); - uvalue = byte_get (data++, 1); - display_block (data, uvalue); + SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end); + display_block (data, uvalue, end); data += uvalue; break; case DW_OP_GNU_regval_type: - uvalue = read_leb128 (data, &bytes_read, 0); + uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; printf ("DW_OP_GNU_regval_type: %s (%s)", dwarf_vmatoa ("u", uvalue), regname (uvalue, 1)); - uvalue = read_leb128 (data, &bytes_read, 0); + uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; printf (" <0x%s>", dwarf_vmatoa ("x", cu_offset + uvalue)); break; case DW_OP_GNU_deref_type: - printf ("DW_OP_GNU_deref_type: %ld", (long) byte_get (data++, 1)); - uvalue = read_leb128 (data, &bytes_read, 0); + SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end); + printf ("DW_OP_GNU_deref_type: %ld", (long) uvalue); + uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; printf (" <0x%s>", dwarf_vmatoa ("x", cu_offset + uvalue)); break; case DW_OP_GNU_convert: - uvalue = read_leb128 (data, &bytes_read, 0); + uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; printf ("DW_OP_GNU_convert <0x%s>", dwarf_vmatoa ("x", uvalue ? cu_offset + uvalue : 0)); break; case DW_OP_GNU_reinterpret: - uvalue = read_leb128 (data, &bytes_read, 0); + uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; printf ("DW_OP_GNU_reinterpret <0x%s>", dwarf_vmatoa ("x", uvalue ? cu_offset + uvalue : 0)); break; case DW_OP_GNU_parameter_ref: + SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end); printf ("DW_OP_GNU_parameter_ref: <0x%s>", - dwarf_vmatoa ("x", cu_offset + byte_get (data, 4))); - data += 4; + dwarf_vmatoa ("x", cu_offset + uvalue)); break; case DW_OP_GNU_addr_index: - uvalue = read_leb128 (data, &bytes_read, 0); + uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; printf ("DW_OP_GNU_addr_index <0x%s>", dwarf_vmatoa ("x", uvalue)); break; case DW_OP_GNU_const_index: - uvalue = read_leb128 (data, &bytes_read, 0); + uvalue = read_uleb128 (data, &bytes_read, end); data += bytes_read; printf ("DW_OP_GNU_const_index <0x%s>", dwarf_vmatoa ("x", uvalue)); break; @@ -1318,10 +1421,39 @@ find_cu_tu_set_v2 (dwarf_vma cu_offset, int do_types) return NULL; } +/* Add INC to HIGH_BITS:LOW_BITS. */ +static void +add64 (dwarf_vma * high_bits, dwarf_vma * low_bits, dwarf_vma inc) +{ + dwarf_vma tmp = * low_bits; + + tmp += inc; + + /* FIXME: There is probably a better way of handling this: + + We need to cope with dwarf_vma being a 32-bit or 64-bit + type. Plus regardless of its size LOW_BITS is meant to + only hold 32-bits, so if there is overflow or wrap around + we must propagate into HIGH_BITS. */ + if (tmp < * low_bits) + { + ++ * high_bits; + } + else if (sizeof (tmp) > 8 + && (tmp >> 31) > 1) + { + ++ * high_bits; + tmp &= 0xFFFFFFFF; + } + + * low_bits = tmp; +} + static unsigned char * read_and_display_attr_value (unsigned long attribute, unsigned long form, unsigned char * data, + unsigned char * end, dwarf_vma cu_offset, dwarf_vma pointer_size, dwarf_vma offset_size, @@ -1336,6 +1468,12 @@ read_and_display_attr_value (unsigned long attribute, unsigned char * orig_data = data; unsigned int bytes_read; + if (data == end && form != DW_FORM_flag_present) + { + warn (_("corrupt attribute\n")); + return data; + } + switch (form) { default: @@ -1343,31 +1481,23 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_ref_addr: if (dwarf_version == 2) - { - uvalue = byte_get (data, pointer_size); - data += pointer_size; - } + SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end); else if (dwarf_version == 3 || dwarf_version == 4) - { - uvalue = byte_get (data, offset_size); - data += offset_size; - } + SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end); else error (_("Internal error: DWARF version is not 2, 3 or 4.\n")); break; case DW_FORM_addr: - uvalue = byte_get (data, pointer_size); - data += pointer_size; + SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end); break; case DW_FORM_strp: case DW_FORM_sec_offset: case DW_FORM_GNU_ref_alt: case DW_FORM_GNU_strp_alt: - uvalue = byte_get (data, offset_size); - data += offset_size; + SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end); break; case DW_FORM_flag_present: @@ -1377,49 +1507,47 @@ read_and_display_attr_value (unsigned long attribute, case DW_FORM_ref1: case DW_FORM_flag: case DW_FORM_data1: - uvalue = byte_get (data++, 1); + SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end); break; case DW_FORM_ref2: case DW_FORM_data2: - uvalue = byte_get (data, 2); - data += 2; + SAFE_BYTE_GET_AND_INC (uvalue, data, 2, end); break; case DW_FORM_ref4: case DW_FORM_data4: - uvalue = byte_get (data, 4); - data += 4; + SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end); break; case DW_FORM_sdata: - uvalue = read_leb128 (data, & bytes_read, 1); + uvalue = read_sleb128 (data, & bytes_read, end); data += bytes_read; break; case DW_FORM_GNU_str_index: - uvalue = read_leb128 (data, & bytes_read, 0); + uvalue = read_uleb128 (data, & bytes_read, end); data += bytes_read; break; case DW_FORM_ref_udata: case DW_FORM_udata: - uvalue = read_leb128 (data, & bytes_read, 0); + uvalue = read_uleb128 (data, & bytes_read, end); data += bytes_read; break; case DW_FORM_indirect: - form = read_leb128 (data, & bytes_read, 0); + form = read_uleb128 (data, & bytes_read, end); data += bytes_read; if (!do_loc) printf (" %s", get_FORM_name (form)); - return read_and_display_attr_value (attribute, form, data, + return read_and_display_attr_value (attribute, form, data, end, cu_offset, pointer_size, offset_size, dwarf_version, debug_info_p, do_loc, section, this_set); case DW_FORM_GNU_addr_index: - uvalue = read_leb128 (data, & bytes_read, 0); + uvalue = read_uleb128 (data, & bytes_read, end); data += bytes_read; break; } @@ -1466,64 +1594,70 @@ read_and_display_attr_value (unsigned long attribute, if (!do_loc) { dwarf_vma high_bits; + dwarf_vma utmp; char buf[64]; - byte_get_64 (data, &high_bits, &uvalue); + SAFE_BYTE_GET64 (data, &high_bits, &uvalue, end); + utmp = uvalue; + if (form == DW_FORM_ref8) + add64 (& high_bits, & utmp, cu_offset); printf (" 0x%s", - dwarf_vmatoa64 (high_bits, uvalue, buf, sizeof (buf))); + dwarf_vmatoa64 (high_bits, utmp, buf, sizeof (buf))); } + if ((do_loc || do_debug_loc || do_debug_ranges) && num_debug_info_entries == 0) { if (sizeof (uvalue) == 8) - uvalue = byte_get (data, 8); + SAFE_BYTE_GET (uvalue, data, 8, end); else error (_("DW_FORM_data8 is unsupported when sizeof (dwarf_vma) != 8\n")); } + data += 8; break; case DW_FORM_string: if (!do_loc) - printf (" %s", data); - data += strlen ((char *) data) + 1; + printf (" %.*s", (int) (end - data), data); + data += strnlen ((char *) data, end - data) + 1; break; case DW_FORM_block: case DW_FORM_exprloc: - uvalue = read_leb128 (data, & bytes_read, 0); + uvalue = read_uleb128 (data, & bytes_read, end); block_start = data + bytes_read; if (do_loc) data = block_start + uvalue; else - data = display_block (block_start, uvalue); + data = display_block (block_start, uvalue, end); break; case DW_FORM_block1: - uvalue = byte_get (data, 1); + SAFE_BYTE_GET (uvalue, data, 1, end); block_start = data + 1; if (do_loc) data = block_start + uvalue; else - data = display_block (block_start, uvalue); + data = display_block (block_start, uvalue, end); break; case DW_FORM_block2: - uvalue = byte_get (data, 2); + SAFE_BYTE_GET (uvalue, data, 2, end); block_start = data + 2; if (do_loc) data = block_start + uvalue; else - data = display_block (block_start, uvalue); + data = display_block (block_start, uvalue, end); break; case DW_FORM_block4: - uvalue = byte_get (data, 4); + SAFE_BYTE_GET (uvalue, data, 4, end); block_start = data + 4; if (do_loc) data = block_start + uvalue; else - data = display_block (block_start, uvalue); + data = display_block (block_start, uvalue, end); break; case DW_FORM_strp: @@ -1561,7 +1695,7 @@ read_and_display_attr_value (unsigned long attribute, dwarf_vma high_bits; char buf[64]; - byte_get_64 (data, &high_bits, &uvalue); + SAFE_BYTE_GET64 (data, &high_bits, &uvalue, end); printf (" signature: 0x%s", dwarf_vmatoa64 (high_bits, uvalue, buf, sizeof (buf))); } @@ -1671,11 +1805,10 @@ read_and_display_attr_value (unsigned long attribute, return data; /* For some attributes we can display further information. */ - printf ("\t"); - switch (attribute) { case DW_AT_inline: + printf ("\t"); switch (uvalue) { case DW_INL_not_inlined: @@ -1698,6 +1831,7 @@ read_and_display_attr_value (unsigned long attribute, break; case DW_AT_language: + printf ("\t"); switch (uvalue) { /* Ordered by the numeric value of these constants. */ @@ -1741,6 +1875,7 @@ read_and_display_attr_value (unsigned long attribute, break; case DW_AT_encoding: + printf ("\t"); switch (uvalue) { case DW_ATE_void: printf ("(void)"); break; @@ -1781,6 +1916,7 @@ read_and_display_attr_value (unsigned long attribute, break; case DW_AT_accessibility: + printf ("\t"); switch (uvalue) { case DW_ACCESS_public: printf ("(public)"); break; @@ -1793,6 +1929,7 @@ read_and_display_attr_value (unsigned long attribute, break; case DW_AT_visibility: + printf ("\t"); switch (uvalue) { case DW_VIS_local: printf ("(local)"); break; @@ -1803,6 +1940,7 @@ read_and_display_attr_value (unsigned long attribute, break; case DW_AT_virtuality: + printf ("\t"); switch (uvalue) { case DW_VIRTUALITY_none: printf ("(none)"); break; @@ -1813,6 +1951,7 @@ read_and_display_attr_value (unsigned long attribute, break; case DW_AT_identifier_case: + printf ("\t"); switch (uvalue) { case DW_ID_case_sensitive: printf ("(case_sensitive)"); break; @@ -1824,6 +1963,7 @@ read_and_display_attr_value (unsigned long attribute, break; case DW_AT_calling_convention: + printf ("\t"); switch (uvalue) { case DW_CC_normal: printf ("(normal)"); break; @@ -1839,6 +1979,7 @@ read_and_display_attr_value (unsigned long attribute, break; case DW_AT_ordering: + printf ("\t"); switch (uvalue) { case -1: printf (_("(undefined)")); break; @@ -1864,7 +2005,7 @@ read_and_display_attr_value (unsigned long attribute, if ((dwarf_version < 4 && (form == DW_FORM_data4 || form == DW_FORM_data8)) || form == DW_FORM_sec_offset) - printf (_("(location list)")); + printf (_(" (location list)")); /* Fall through. */ case DW_AT_allocated: case DW_AT_associated: @@ -1876,7 +2017,7 @@ read_and_display_attr_value (unsigned long attribute, { int need_frame_base; - printf ("("); + printf ("\t("); need_frame_base = decode_location_expression (block_start, pointer_size, offset_size, @@ -1910,9 +2051,9 @@ read_and_display_attr_value (unsigned long attribute, unsigned long abbrev_number; abbrev_entry * entry; - abbrev_number = read_leb128 (section->start + uvalue, NULL, 0); + abbrev_number = read_uleb128 (section->start + uvalue, NULL, end); - printf (_("[Abbrev Number: %ld"), abbrev_number); + printf (_("\t[Abbrev Number: %ld"), abbrev_number); /* Don't look up abbrev for DW_FORM_ref_addr, as it very often will use different abbrev table, and we don't track .debug_info chunks yet. */ @@ -1966,6 +2107,7 @@ static unsigned char * read_and_display_attr (unsigned long attribute, unsigned long form, unsigned char * data, + unsigned char * end, dwarf_vma cu_offset, dwarf_vma pointer_size, dwarf_vma offset_size, @@ -1977,8 +2119,8 @@ read_and_display_attr (unsigned long attribute, { if (!do_loc) printf (" %-18s:", get_AT_name (attribute)); - data = read_and_display_attr_value (attribute, form, data, cu_offset, - pointer_size, offset_size, + data = read_and_display_attr_value (attribute, form, data, end, + cu_offset, pointer_size, offset_size, dwarf_version, debug_info_p, do_loc, section, this_set); if (!do_loc) @@ -2017,11 +2159,11 @@ process_debug_info (struct dwarf_section *section, /* Read the first 4 bytes. For a 32-bit DWARF section, this will be the length. For a 64-bit DWARF section, it'll be the escape code 0xffffffff followed by an 8 byte length. */ - length = byte_get (section_begin, 4); + SAFE_BYTE_GET (length, section_begin, 4, end); if (length == 0xffffffff) { - length = byte_get (section_begin + 4, 8); + SAFE_BYTE_GET (length, section_begin + 4, 8, end); section_begin += length + 12; } else if (length >= 0xfffffff0 && length < 0xffffffff) @@ -2088,7 +2230,7 @@ process_debug_info (struct dwarf_section *section, unsigned char *tags; int level, last_level, saved_level; dwarf_vma cu_offset; - int offset_size; + unsigned int offset_size; int initial_length_size; dwarf_vma signature_high = 0; dwarf_vma signature_low = 0; @@ -2099,13 +2241,11 @@ process_debug_info (struct dwarf_section *section, hdrptr = start; - compunit.cu_length = byte_get (hdrptr, 4); - hdrptr += 4; + SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 4, end); if (compunit.cu_length == 0xffffffff) { - compunit.cu_length = byte_get (hdrptr, 8); - hdrptr += 8; + SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 8, end); offset_size = 8; initial_length_size = 12; } @@ -2115,15 +2255,13 @@ process_debug_info (struct dwarf_section *section, initial_length_size = 4; } - compunit.cu_version = byte_get (hdrptr, 2); - hdrptr += 2; + SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end); cu_offset = start - section_begin; this_set = find_cu_tu_set_v2 (cu_offset, do_types); - compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size); - hdrptr += offset_size; + SAFE_BYTE_GET_AND_INC (compunit.cu_abbrev_offset, hdrptr, offset_size, end); if (this_set == NULL) { @@ -2136,15 +2274,13 @@ process_debug_info (struct dwarf_section *section, abbrev_size = this_set->section_sizes [DW_SECT_ABBREV]; } - compunit.cu_pointer_size = byte_get (hdrptr, 1); - hdrptr += 1; + SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end); if (do_types) { - byte_get_64 (hdrptr, &signature_high, &signature_low); - hdrptr += 8; - type_offset = byte_get (hdrptr, offset_size); - hdrptr += offset_size; + SAFE_BYTE_GET64 (hdrptr, &signature_high, &signature_low, end); + hdrptr += 8; + SAFE_BYTE_GET_AND_INC (type_offset, hdrptr, offset_size, end); } if ((do_loc || do_debug_loc || do_debug_ranges) @@ -2234,8 +2370,7 @@ process_debug_info (struct dwarf_section *section, free_abbrevs (); - /* Process the abbrevs used by this compilation unit. DWARF - sections under Mach-O have non-zero addresses. */ + /* Process the abbrevs used by this compilation unit. */ if (compunit.cu_abbrev_offset >= abbrev_size) warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than abbrev section size (%lx)\n"), (unsigned long) compunit.cu_abbrev_offset, @@ -2261,7 +2396,7 @@ process_debug_info (struct dwarf_section *section, die_offset = tags - section_begin; - abbrev_number = read_leb128 (tags, & bytes_read, 0); + abbrev_number = read_uleb128 (tags, & bytes_read, start); tags += bytes_read; /* A null DIE marks the end of a list of siblings or it may also be @@ -2280,7 +2415,9 @@ process_debug_info (struct dwarf_section *section, break; } - if (!do_loc && die_offset >= dwarf_start_die) + if (!do_loc && die_offset >= dwarf_start_die + && (dwarf_cutoff_level == -1 + || level < dwarf_cutoff_level)) printf (_(" <%d><%lx>: Abbrev Number: 0\n"), level, die_offset); @@ -2378,6 +2515,7 @@ process_debug_info (struct dwarf_section *section, tags = read_and_display_attr (attr->attribute, attr->form, tags, + end, cu_offset, compunit.cu_pointer_size, offset_size, @@ -2444,39 +2582,33 @@ load_debug_info (void * file) return 0; } -static int -display_debug_lines_raw (struct dwarf_section *section, - unsigned char *data, - unsigned char *end) -{ - unsigned char *start = section->start; - - printf (_("Raw dump of debug contents of section %s:\n\n"), - section->name); +/* Read a DWARF .debug_line section header starting at DATA. + Upon success returns an updated DATA pointer and the LINFO + structure and the END_OF_SEQUENCE pointer will be filled in. + Otherwise returns NULL. */ - while (data < end) - { - DWARF2_Internal_LineInfo linfo; - unsigned char *standard_opcodes; - unsigned char *end_of_sequence; - unsigned char *hdrptr; - unsigned long hdroff; - int initial_length_size; - int offset_size; - int i; +static unsigned char * +read_debug_line_header (struct dwarf_section * section, + unsigned char * data, + unsigned char * end, + DWARF2_Internal_LineInfo * linfo, + unsigned char ** end_of_sequence) +{ + unsigned char *hdrptr; + unsigned int offset_size; + unsigned int initial_length_size; + /* Extract information from the Line Number Program Header. + (section 6.2.4 in the Dwarf3 doc). */ hdrptr = data; - hdroff = hdrptr - start; - /* Check the length of the block. */ - linfo.li_length = byte_get (hdrptr, 4); - hdrptr += 4; + /* Get and check the length of the block. */ + SAFE_BYTE_GET_AND_INC (linfo->li_length, hdrptr, 4, end); - if (linfo.li_length == 0xffffffff) + if (linfo->li_length == 0xffffffff) { /* This section is 64-bit DWARF 3. */ - linfo.li_length = byte_get (hdrptr, 8); - hdrptr += 8; + SAFE_BYTE_GET_AND_INC (linfo->li_length, hdrptr, 8, end); offset_size = 8; initial_length_size = 12; } @@ -2486,316 +2618,389 @@ display_debug_lines_raw (struct dwarf_section *section, initial_length_size = 4; } - if (linfo.li_length + initial_length_size > section->size) + if (linfo->li_length + initial_length_size > section->size) { - warn - (_("The information in section %s appears to be corrupt - the section is too small\n"), - section->name); - return 0; + /* If the length is just a bias against the initial_length_size then + this means that the field has a relocation against it which has not + been applied. (Ie we are dealing with an object file, not a linked + binary). Do not complain but instead assume that the rest of the + section applies to this particular header. */ + if (linfo->li_length == - initial_length_size) + { + linfo->li_length = section->size - initial_length_size; + } + else + { + warn (_("The line info appears to be corrupt - " + "the section is too small\n")); + return NULL; } + } + + /* Get and check the version number. */ + SAFE_BYTE_GET_AND_INC (linfo->li_version, hdrptr, 2, end); - /* Check its version number. */ - linfo.li_version = byte_get (hdrptr, 2); - hdrptr += 2; - if (linfo.li_version != 2 - && linfo.li_version != 3 - && linfo.li_version != 4) + if (linfo->li_version != 2 + && linfo->li_version != 3 + && linfo->li_version != 4) { warn (_("Only DWARF version 2, 3 and 4 line info is currently supported.\n")); - return 0; + return NULL; } - linfo.li_prologue_length = byte_get (hdrptr, offset_size); - hdrptr += offset_size; - linfo.li_min_insn_length = byte_get (hdrptr, 1); - hdrptr++; - if (linfo.li_version >= 4) + SAFE_BYTE_GET_AND_INC (linfo->li_prologue_length, hdrptr, offset_size, end); + SAFE_BYTE_GET_AND_INC (linfo->li_min_insn_length, hdrptr, 1, end); + + if (linfo->li_version >= 4) { - linfo.li_max_ops_per_insn = byte_get (hdrptr, 1); - hdrptr++; - if (linfo.li_max_ops_per_insn == 0) + SAFE_BYTE_GET_AND_INC (linfo->li_max_ops_per_insn, hdrptr, 1, end); + + if (linfo->li_max_ops_per_insn == 0) { warn (_("Invalid maximum operations per insn.\n")); - return 0; + return NULL; } } else - linfo.li_max_ops_per_insn = 1; - linfo.li_default_is_stmt = byte_get (hdrptr, 1); - hdrptr++; - linfo.li_line_base = byte_get (hdrptr, 1); - hdrptr++; - linfo.li_line_range = byte_get (hdrptr, 1); - hdrptr++; - linfo.li_opcode_base = byte_get (hdrptr, 1); - hdrptr++; - - /* Sign extend the line base field. */ - linfo.li_line_base <<= 24; - linfo.li_line_base >>= 24; - - printf (_(" Offset: 0x%lx\n"), hdroff); - printf (_(" Length: %ld\n"), (long) linfo.li_length); - printf (_(" DWARF Version: %d\n"), linfo.li_version); - printf (_(" Prologue Length: %d\n"), linfo.li_prologue_length); - printf (_(" Minimum Instruction Length: %d\n"), linfo.li_min_insn_length); - if (linfo.li_version >= 4) - printf (_(" Maximum Ops per Instruction: %d\n"), linfo.li_max_ops_per_insn); - printf (_(" Initial value of 'is_stmt': %d\n"), linfo.li_default_is_stmt); - printf (_(" Line Base: %d\n"), linfo.li_line_base); - printf (_(" Line Range: %d\n"), linfo.li_line_range); - printf (_(" Opcode Base: %d\n"), linfo.li_opcode_base); + linfo->li_max_ops_per_insn = 1; - end_of_sequence = data + linfo.li_length + initial_length_size; + SAFE_BYTE_GET_AND_INC (linfo->li_default_is_stmt, hdrptr, 1, end); + SAFE_BYTE_GET_AND_INC (linfo->li_line_base, hdrptr, 1, end); + SAFE_BYTE_GET_AND_INC (linfo->li_line_range, hdrptr, 1, end); + SAFE_BYTE_GET_AND_INC (linfo->li_opcode_base, hdrptr, 1, end); - reset_state_machine (linfo.li_default_is_stmt); + /* Sign extend the line base field. */ + linfo->li_line_base <<= 24; + linfo->li_line_base >>= 24; - /* Display the contents of the Opcodes table. */ - standard_opcodes = hdrptr; + * end_of_sequence = data + linfo->li_length + initial_length_size; + return hdrptr; +} - printf (_("\n Opcodes:\n")); +static int +display_debug_lines_raw (struct dwarf_section *section, + unsigned char *data, + unsigned char *end) +{ + unsigned char *start = section->start; - for (i = 1; i < linfo.li_opcode_base; i++) - printf (_(" Opcode %d has %d args\n"), i, standard_opcodes[i - 1]); + printf (_("Raw dump of debug contents of section %s:\n\n"), + section->name); - /* Display the contents of the Directory table. */ - data = standard_opcodes + linfo.li_opcode_base - 1; + while (data < end) + { + static DWARF2_Internal_LineInfo saved_linfo; + DWARF2_Internal_LineInfo linfo; + unsigned char *standard_opcodes; + unsigned char *end_of_sequence; + unsigned int last_dir_entry = 0; + int i; - if (*data == 0) - printf (_("\n The Directory Table is empty.\n")); - else + if (const_strneq (section->name, ".debug_line.") + /* Note: the following does not apply to .debug_line.dwo sections. + These are full debug_line sections. */ + && strcmp (section->name, ".debug_line.dwo") != 0) { - printf (_("\n The Directory Table:\n")); - - while (*data != 0) - { - printf (" %s\n", data); - - data += strlen ((char *) data) + 1; - } + /* Sections named .debug_line. are fragments of a .debug_line + section containing just the Line Number Statements. They are + created by the assembler and intended to be used alongside gcc's + -ffunction-sections command line option. When the linker's + garbage collection decides to discard a .text. section it + can then also discard the line number information in .debug_line.. + + Since the section is a fragment it does not have the details + needed to fill out a LineInfo structure, so instead we use the + details from the last full debug_line section that we processed. */ + end_of_sequence = end; + standard_opcodes = NULL; + linfo = saved_linfo; + reset_state_machine (linfo.li_default_is_stmt); } - - /* Skip the NUL at the end of the table. */ - data++; - - /* Display the contents of the File Name table. */ - if (*data == 0) - printf (_("\n The File Name Table is empty.\n")); else { - printf (_("\n The File Name Table:\n")); - printf (_(" Entry\tDir\tTime\tSize\tName\n")); + unsigned char * hdrptr; - while (*data != 0) - { - unsigned char *name; - unsigned int bytes_read; + if ((hdrptr = read_debug_line_header (section, data, end, & linfo, + & end_of_sequence)) == NULL) + return 0; - printf (" %d\t", ++state_machine_regs.last_file_entry); - name = data; - - data += strlen ((char *) data) + 1; - - printf ("%s\t", - dwarf_vmatoa ("u", read_leb128 (data, & bytes_read, 0))); - data += bytes_read; - printf ("%s\t", - dwarf_vmatoa ("u", read_leb128 (data, & bytes_read, 0))); - data += bytes_read; - printf ("%s\t", - dwarf_vmatoa ("u", read_leb128 (data, & bytes_read, 0))); - data += bytes_read; - printf ("%s\n", name); - } - } + printf (_(" Offset: 0x%lx\n"), (long)(data - start)); + printf (_(" Length: %ld\n"), (long) linfo.li_length); + printf (_(" DWARF Version: %d\n"), linfo.li_version); + printf (_(" Prologue Length: %d\n"), linfo.li_prologue_length); + printf (_(" Minimum Instruction Length: %d\n"), linfo.li_min_insn_length); + if (linfo.li_version >= 4) + printf (_(" Maximum Ops per Instruction: %d\n"), linfo.li_max_ops_per_insn); + printf (_(" Initial value of 'is_stmt': %d\n"), linfo.li_default_is_stmt); + printf (_(" Line Base: %d\n"), linfo.li_line_base); + printf (_(" Line Range: %d\n"), linfo.li_line_range); + printf (_(" Opcode Base: %d\n"), linfo.li_opcode_base); - /* Skip the NUL at the end of the table. */ - data++; + reset_state_machine (linfo.li_default_is_stmt); - /* Now display the statements. */ - printf (_("\n Line Number Statements:\n")); + /* Display the contents of the Opcodes table. */ + standard_opcodes = hdrptr; - while (data < end_of_sequence) - { - unsigned char op_code; - dwarf_signed_vma adv; - dwarf_vma uladv; - unsigned int bytes_read; + printf (_("\n Opcodes:\n")); - op_code = *data++; + for (i = 1; i < linfo.li_opcode_base; i++) + printf (_(" Opcode %d has %d args\n"), i, standard_opcodes[i - 1]); - if (op_code >= linfo.li_opcode_base) - { - op_code -= linfo.li_opcode_base; - uladv = (op_code / linfo.li_line_range); - if (linfo.li_max_ops_per_insn == 1) - { - uladv *= linfo.li_min_insn_length; - state_machine_regs.address += uladv; - printf (_(" Special opcode %d: " - "advance Address by %s to 0x%s"), - op_code, dwarf_vmatoa ("u", uladv), - dwarf_vmatoa ("x", state_machine_regs.address)); - } - else - { - state_machine_regs.address - += ((state_machine_regs.op_index + uladv) - / linfo.li_max_ops_per_insn) - * linfo.li_min_insn_length; - state_machine_regs.op_index - = (state_machine_regs.op_index + uladv) - % linfo.li_max_ops_per_insn; - printf (_(" Special opcode %d: " - "advance Address by %s to 0x%s[%d]"), - op_code, dwarf_vmatoa ("u", uladv), - dwarf_vmatoa ("x", state_machine_regs.address), - state_machine_regs.op_index); - } - adv = (op_code % linfo.li_line_range) + linfo.li_line_base; - state_machine_regs.line += adv; - printf (_(" and Line by %s to %d\n"), - dwarf_vmatoa ("d", adv), state_machine_regs.line); - } - else switch (op_code) - { - case DW_LNS_extended_op: - data += process_extended_line_op (data, linfo.li_default_is_stmt); - break; + /* Display the contents of the Directory table. */ + data = standard_opcodes + linfo.li_opcode_base - 1; - case DW_LNS_copy: - printf (_(" Copy\n")); - break; + if (*data == 0) + printf (_("\n The Directory Table is empty.\n")); + else + { + printf (_("\n The Directory Table (offset 0x%lx):\n"), + (long)(data - start)); - case DW_LNS_advance_pc: - uladv = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - if (linfo.li_max_ops_per_insn == 1) + while (*data != 0) { - uladv *= linfo.li_min_insn_length; - state_machine_regs.address += uladv; - printf (_(" Advance PC by %s to 0x%s\n"), - dwarf_vmatoa ("u", uladv), - dwarf_vmatoa ("x", state_machine_regs.address)); - } - else - { - state_machine_regs.address - += ((state_machine_regs.op_index + uladv) - / linfo.li_max_ops_per_insn) - * linfo.li_min_insn_length; - state_machine_regs.op_index - = (state_machine_regs.op_index + uladv) - % linfo.li_max_ops_per_insn; - printf (_(" Advance PC by %s to 0x%s[%d]\n"), - dwarf_vmatoa ("u", uladv), - dwarf_vmatoa ("x", state_machine_regs.address), - state_machine_regs.op_index); + printf (" %d\t%s\n", ++last_dir_entry, data); + + data += strnlen ((char *) data, end - data) + 1; } - break; + } - case DW_LNS_advance_line: - adv = read_sleb128 (data, & bytes_read); - data += bytes_read; - state_machine_regs.line += adv; - printf (_(" Advance Line by %s to %d\n"), - dwarf_vmatoa ("d", adv), - state_machine_regs.line); - break; + /* Skip the NUL at the end of the table. */ + data++; - case DW_LNS_set_file: - adv = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - printf (_(" Set File Name to entry %s in the File Name Table\n"), - dwarf_vmatoa ("d", adv)); - state_machine_regs.file = adv; - break; + /* Display the contents of the File Name table. */ + if (*data == 0) + printf (_("\n The File Name Table is empty.\n")); + else + { + printf (_("\n The File Name Table (offset 0x%lx):\n"), + (long)(data - start)); + printf (_(" Entry\tDir\tTime\tSize\tName\n")); - case DW_LNS_set_column: - uladv = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - printf (_(" Set column to %s\n"), - dwarf_vmatoa ("u", uladv)); - state_machine_regs.column = uladv; - break; + while (*data != 0) + { + unsigned char *name; + unsigned int bytes_read; - case DW_LNS_negate_stmt: - adv = state_machine_regs.is_stmt; - adv = ! adv; - printf (_(" Set is_stmt to %s\n"), dwarf_vmatoa ("d", adv)); - state_machine_regs.is_stmt = adv; - break; + printf (" %d\t", ++state_machine_regs.last_file_entry); + name = data; + data += strnlen ((char *) data, end - data) + 1; - case DW_LNS_set_basic_block: - printf (_(" Set basic block\n")); - state_machine_regs.basic_block = 1; - break; + printf ("%s\t", + dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); + data += bytes_read; + printf ("%s\t", + dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); + data += bytes_read; + printf ("%s\t", + dwarf_vmatoa ("u", read_uleb128 (data, & bytes_read, end))); + data += bytes_read; + printf ("%s\n", name); - case DW_LNS_const_add_pc: - uladv = ((255 - linfo.li_opcode_base) / linfo.li_line_range); - if (linfo.li_max_ops_per_insn) - { - uladv *= linfo.li_min_insn_length; - state_machine_regs.address += uladv; - printf (_(" Advance PC by constant %s to 0x%s\n"), - dwarf_vmatoa ("u", uladv), - dwarf_vmatoa ("x", state_machine_regs.address)); - } - else - { - state_machine_regs.address - += ((state_machine_regs.op_index + uladv) - / linfo.li_max_ops_per_insn) - * linfo.li_min_insn_length; - state_machine_regs.op_index - = (state_machine_regs.op_index + uladv) - % linfo.li_max_ops_per_insn; - printf (_(" Advance PC by constant %s to 0x%s[%d]\n"), - dwarf_vmatoa ("u", uladv), - dwarf_vmatoa ("x", state_machine_regs.address), - state_machine_regs.op_index); + if (data == end) + { + warn (_("Corrupt file name table entry\n")); + break; + } } - break; + } - case DW_LNS_fixed_advance_pc: - uladv = byte_get (data, 2); - data += 2; - state_machine_regs.address += uladv; - state_machine_regs.op_index = 0; - printf (_(" Advance PC by fixed size amount %s to 0x%s\n"), - dwarf_vmatoa ("u", uladv), - dwarf_vmatoa ("x", state_machine_regs.address)); - break; + /* Skip the NUL at the end of the table. */ + data++; + putchar ('\n'); + saved_linfo = linfo; + } - case DW_LNS_set_prologue_end: - printf (_(" Set prologue_end to true\n")); - break; + /* Now display the statements. */ + if (data >= end_of_sequence) + printf (_(" No Line Number Statements.\n")); + else + { + printf (_(" Line Number Statements:\n")); - case DW_LNS_set_epilogue_begin: - printf (_(" Set epilogue_begin to true\n")); - break; + while (data < end_of_sequence) + { + unsigned char op_code; + dwarf_signed_vma adv; + dwarf_vma uladv; + unsigned int bytes_read; - case DW_LNS_set_isa: - uladv = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - printf (_(" Set ISA to %s\n"), dwarf_vmatoa ("u", uladv)); - break; + printf (" [0x%08lx]", (long)(data - start)); - default: - printf (_(" Unknown opcode %d with operands: "), op_code); + op_code = *data++; - for (i = standard_opcodes[op_code - 1]; i > 0 ; --i) + if (op_code >= linfo.li_opcode_base) { - printf ("0x%s%s", dwarf_vmatoa ("x", read_leb128 (data, - &bytes_read, 0)), - i == 1 ? "" : ", "); - data += bytes_read; + op_code -= linfo.li_opcode_base; + uladv = (op_code / linfo.li_line_range); + if (linfo.li_max_ops_per_insn == 1) + { + uladv *= linfo.li_min_insn_length; + state_machine_regs.address += uladv; + printf (_(" Special opcode %d: " + "advance Address by %s to 0x%s"), + op_code, dwarf_vmatoa ("u", uladv), + dwarf_vmatoa ("x", state_machine_regs.address)); + } + else + { + state_machine_regs.address + += ((state_machine_regs.op_index + uladv) + / linfo.li_max_ops_per_insn) + * linfo.li_min_insn_length; + state_machine_regs.op_index + = (state_machine_regs.op_index + uladv) + % linfo.li_max_ops_per_insn; + printf (_(" Special opcode %d: " + "advance Address by %s to 0x%s[%d]"), + op_code, dwarf_vmatoa ("u", uladv), + dwarf_vmatoa ("x", state_machine_regs.address), + state_machine_regs.op_index); + } + adv = (op_code % linfo.li_line_range) + linfo.li_line_base; + state_machine_regs.line += adv; + printf (_(" and Line by %s to %d\n"), + dwarf_vmatoa ("d", adv), state_machine_regs.line); } - putchar ('\n'); - break; + else switch (op_code) + { + case DW_LNS_extended_op: + data += process_extended_line_op (data, linfo.li_default_is_stmt, end); + break; + + case DW_LNS_copy: + printf (_(" Copy\n")); + break; + + case DW_LNS_advance_pc: + uladv = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + if (linfo.li_max_ops_per_insn == 1) + { + uladv *= linfo.li_min_insn_length; + state_machine_regs.address += uladv; + printf (_(" Advance PC by %s to 0x%s\n"), + dwarf_vmatoa ("u", uladv), + dwarf_vmatoa ("x", state_machine_regs.address)); + } + else + { + state_machine_regs.address + += ((state_machine_regs.op_index + uladv) + / linfo.li_max_ops_per_insn) + * linfo.li_min_insn_length; + state_machine_regs.op_index + = (state_machine_regs.op_index + uladv) + % linfo.li_max_ops_per_insn; + printf (_(" Advance PC by %s to 0x%s[%d]\n"), + dwarf_vmatoa ("u", uladv), + dwarf_vmatoa ("x", state_machine_regs.address), + state_machine_regs.op_index); + } + break; + + case DW_LNS_advance_line: + adv = read_sleb128 (data, & bytes_read, end); + data += bytes_read; + state_machine_regs.line += adv; + printf (_(" Advance Line by %s to %d\n"), + dwarf_vmatoa ("d", adv), + state_machine_regs.line); + break; + + case DW_LNS_set_file: + adv = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + printf (_(" Set File Name to entry %s in the File Name Table\n"), + dwarf_vmatoa ("d", adv)); + state_machine_regs.file = adv; + break; + + case DW_LNS_set_column: + uladv = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + printf (_(" Set column to %s\n"), + dwarf_vmatoa ("u", uladv)); + state_machine_regs.column = uladv; + break; + + case DW_LNS_negate_stmt: + adv = state_machine_regs.is_stmt; + adv = ! adv; + printf (_(" Set is_stmt to %s\n"), dwarf_vmatoa ("d", adv)); + state_machine_regs.is_stmt = adv; + break; + + case DW_LNS_set_basic_block: + printf (_(" Set basic block\n")); + state_machine_regs.basic_block = 1; + break; + + case DW_LNS_const_add_pc: + uladv = ((255 - linfo.li_opcode_base) / linfo.li_line_range); + if (linfo.li_max_ops_per_insn) + { + uladv *= linfo.li_min_insn_length; + state_machine_regs.address += uladv; + printf (_(" Advance PC by constant %s to 0x%s\n"), + dwarf_vmatoa ("u", uladv), + dwarf_vmatoa ("x", state_machine_regs.address)); + } + else + { + state_machine_regs.address + += ((state_machine_regs.op_index + uladv) + / linfo.li_max_ops_per_insn) + * linfo.li_min_insn_length; + state_machine_regs.op_index + = (state_machine_regs.op_index + uladv) + % linfo.li_max_ops_per_insn; + printf (_(" Advance PC by constant %s to 0x%s[%d]\n"), + dwarf_vmatoa ("u", uladv), + dwarf_vmatoa ("x", state_machine_regs.address), + state_machine_regs.op_index); + } + break; + + case DW_LNS_fixed_advance_pc: + SAFE_BYTE_GET_AND_INC (uladv, data, 2, end); + state_machine_regs.address += uladv; + state_machine_regs.op_index = 0; + printf (_(" Advance PC by fixed size amount %s to 0x%s\n"), + dwarf_vmatoa ("u", uladv), + dwarf_vmatoa ("x", state_machine_regs.address)); + break; + + case DW_LNS_set_prologue_end: + printf (_(" Set prologue_end to true\n")); + break; + + case DW_LNS_set_epilogue_begin: + printf (_(" Set epilogue_begin to true\n")); + break; + + case DW_LNS_set_isa: + uladv = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + printf (_(" Set ISA to %s\n"), dwarf_vmatoa ("u", uladv)); + break; + + default: + printf (_(" Unknown opcode %d with operands: "), op_code); + + if (standard_opcodes != NULL) + for (i = standard_opcodes[op_code - 1]; i > 0 ; --i) + { + printf ("0x%s%s", dwarf_vmatoa ("x", read_uleb128 (data, + &bytes_read, end)), + i == 1 ? "" : ", "); + data += bytes_read; + } + putchar ('\n'); + break; + } } + putchar ('\n'); } - putchar ('\n'); } return 1; @@ -2816,6 +3021,8 @@ display_debug_lines_decoded (struct dwarf_section *section, unsigned char *data, unsigned char *end) { + static DWARF2_Internal_LineInfo saved_linfo; + printf (_("Decoded dump of debug contents of section %s:\n\n"), section->name); @@ -2825,188 +3032,136 @@ display_debug_lines_decoded (struct dwarf_section *section, DWARF2_Internal_LineInfo linfo; unsigned char *standard_opcodes; unsigned char *end_of_sequence; - unsigned char *hdrptr; - int initial_length_size; - int offset_size; int i; File_Entry *file_table = NULL; unsigned int n_files = 0; unsigned char **directory_table = NULL; unsigned int n_directories = 0; - hdrptr = data; - - /* Extract information from the Line Number Program Header. - (section 6.2.4 in the Dwarf3 doc). */ - - /* Get the length of this CU's line number information block. */ - linfo.li_length = byte_get (hdrptr, 4); - hdrptr += 4; - - if (linfo.li_length == 0xffffffff) + if (const_strneq (section->name, ".debug_line.") + /* Note: the following does not apply to .debug_line.dwo sections. + These are full debug_line sections. */ + && strcmp (section->name, ".debug_line.dwo") != 0) { - /* This section is 64-bit DWARF 3. */ - linfo.li_length = byte_get (hdrptr, 8); - hdrptr += 8; - offset_size = 8; - initial_length_size = 12; + /* See comment in display_debug_lines_raw(). */ + end_of_sequence = end; + standard_opcodes = NULL; + linfo = saved_linfo; + reset_state_machine (linfo.li_default_is_stmt); } else { - offset_size = 4; - initial_length_size = 4; - } + unsigned char *hdrptr; - if (linfo.li_length + initial_length_size > section->size) - { - warn (_("The line info appears to be corrupt - " - "the section is too small\n")); - return 0; - } - - /* Get this CU's Line Number Block version number. */ - linfo.li_version = byte_get (hdrptr, 2); - hdrptr += 2; - if (linfo.li_version != 2 - && linfo.li_version != 3 - && linfo.li_version != 4) - { - warn (_("Only DWARF version 2, 3 and 4 line info is currently " - "supported.\n")); - return 0; - } - - linfo.li_prologue_length = byte_get (hdrptr, offset_size); - hdrptr += offset_size; - linfo.li_min_insn_length = byte_get (hdrptr, 1); - hdrptr++; - if (linfo.li_version >= 4) - { - linfo.li_max_ops_per_insn = byte_get (hdrptr, 1); - hdrptr++; - if (linfo.li_max_ops_per_insn == 0) - { - warn (_("Invalid maximum operations per insn.\n")); + if ((hdrptr = read_debug_line_header (section, data, end, & linfo, + & end_of_sequence)) == NULL) return 0; - } - } - else - linfo.li_max_ops_per_insn = 1; - linfo.li_default_is_stmt = byte_get (hdrptr, 1); - hdrptr++; - linfo.li_line_base = byte_get (hdrptr, 1); - hdrptr++; - linfo.li_line_range = byte_get (hdrptr, 1); - hdrptr++; - linfo.li_opcode_base = byte_get (hdrptr, 1); - hdrptr++; - /* Sign extend the line base field. */ - linfo.li_line_base <<= 24; - linfo.li_line_base >>= 24; + reset_state_machine (linfo.li_default_is_stmt); - /* Find the end of this CU's Line Number Information Block. */ - end_of_sequence = data + linfo.li_length + initial_length_size; + /* Save a pointer to the contents of the Opcodes table. */ + standard_opcodes = hdrptr; - reset_state_machine (linfo.li_default_is_stmt); + /* Traverse the Directory table just to count entries. */ + data = standard_opcodes + linfo.li_opcode_base - 1; + if (*data != 0) + { + unsigned char *ptr_directory_table = data; - /* Save a pointer to the contents of the Opcodes table. */ - standard_opcodes = hdrptr; + while (*data != 0) + { + data += strnlen ((char *) data, end - data) + 1; + n_directories++; + } - /* Traverse the Directory table just to count entries. */ - data = standard_opcodes + linfo.li_opcode_base - 1; - if (*data != 0) - { - unsigned char *ptr_directory_table = data; + /* Go through the directory table again to save the directories. */ + directory_table = (unsigned char **) + xmalloc (n_directories * sizeof (unsigned char *)); - while (*data != 0) - { - data += strlen ((char *) data) + 1; - n_directories++; + i = 0; + while (*ptr_directory_table != 0) + { + directory_table[i] = ptr_directory_table; + ptr_directory_table += strnlen ((char *) ptr_directory_table, + ptr_directory_table - end) + 1; + i++; + } } + /* Skip the NUL at the end of the table. */ + data++; - /* Go through the directory table again to save the directories. */ - directory_table = (unsigned char **) - xmalloc (n_directories * sizeof (unsigned char *)); + /* Traverse the File Name table just to count the entries. */ + if (*data != 0) + { + unsigned char *ptr_file_name_table = data; - i = 0; - while (*ptr_directory_table != 0) - { - directory_table[i] = ptr_directory_table; - ptr_directory_table += strlen ((char *) ptr_directory_table) + 1; - i++; - } - } - /* Skip the NUL at the end of the table. */ - data++; + while (*data != 0) + { + unsigned int bytes_read; - /* Traverse the File Name table just to count the entries. */ - if (*data != 0) - { - unsigned char *ptr_file_name_table = data; + /* Skip Name, directory index, last modification time and length + of file. */ + data += strnlen ((char *) data, end - data) + 1; + read_uleb128 (data, & bytes_read, end); + data += bytes_read; + read_uleb128 (data, & bytes_read, end); + data += bytes_read; + read_uleb128 (data, & bytes_read, end); + data += bytes_read; - while (*data != 0) - { - unsigned int bytes_read; + n_files++; + } - /* Skip Name, directory index, last modification time and length - of file. */ - data += strlen ((char *) data) + 1; - read_leb128 (data, & bytes_read, 0); - data += bytes_read; - read_leb128 (data, & bytes_read, 0); - data += bytes_read; - read_leb128 (data, & bytes_read, 0); - data += bytes_read; - - n_files++; - } + /* Go through the file table again to save the strings. */ + file_table = (File_Entry *) xmalloc (n_files * sizeof (File_Entry)); - /* Go through the file table again to save the strings. */ - file_table = (File_Entry *) xmalloc (n_files * sizeof (File_Entry)); + i = 0; + while (*ptr_file_name_table != 0) + { + unsigned int bytes_read; + + file_table[i].name = ptr_file_name_table; + ptr_file_name_table += strnlen ((char *) ptr_file_name_table, + end - ptr_file_name_table) + 1; + + /* We are not interested in directory, time or size. */ + file_table[i].directory_index = read_uleb128 (ptr_file_name_table, + & bytes_read, end); + ptr_file_name_table += bytes_read; + file_table[i].modification_date = read_uleb128 (ptr_file_name_table, + & bytes_read, end); + ptr_file_name_table += bytes_read; + file_table[i].length = read_uleb128 (ptr_file_name_table, & bytes_read, end); + ptr_file_name_table += bytes_read; + i++; + } + i = 0; - i = 0; - while (*ptr_file_name_table != 0) - { - unsigned int bytes_read; - - file_table[i].name = ptr_file_name_table; - ptr_file_name_table += strlen ((char *) ptr_file_name_table) + 1; - - /* We are not interested in directory, time or size. */ - file_table[i].directory_index = read_leb128 (ptr_file_name_table, - & bytes_read, 0); - ptr_file_name_table += bytes_read; - file_table[i].modification_date = read_leb128 (ptr_file_name_table, - & bytes_read, 0); - ptr_file_name_table += bytes_read; - file_table[i].length = read_leb128 (ptr_file_name_table, & bytes_read, 0); - ptr_file_name_table += bytes_read; - i++; - } - i = 0; + /* Print the Compilation Unit's name and a header. */ + if (directory_table == NULL) + { + printf (_("CU: %s:\n"), file_table[0].name); + printf (_("File name Line number Starting address\n")); + } + else + { + unsigned int ix = file_table[0].directory_index; + const char *directory = ix ? (char *)directory_table[ix - 1] : "."; - /* Print the Compilation Unit's name and a header. */ - if (directory_table == NULL) - { - printf (_("CU: %s:\n"), file_table[0].name); - printf (_("File name Line number Starting address\n")); - } - else - { - unsigned int ix = file_table[0].directory_index; - const char *directory = ix ? (char *)directory_table[ix - 1] : "."; - if (do_wide || strlen (directory) < 76) - printf (_("CU: %s/%s:\n"), directory, file_table[0].name); - else - printf ("%s:\n", file_table[0].name); + if (do_wide || strlen (directory) < 76) + printf (_("CU: %s/%s:\n"), directory, file_table[0].name); + else + printf ("%s:\n", file_table[0].name); - printf (_("File name Line number Starting address\n")); - } - } + printf (_("File name Line number Starting address\n")); + } + } - /* Skip the NUL at the end of the table. */ - data++; + /* Skip the NUL at the end of the table. */ + data++; + + saved_linfo = linfo; + } /* This loop iterates through the Dwarf Line Number Program. */ while (data < end_of_sequence) @@ -3033,10 +3188,10 @@ display_debug_lines_decoded (struct dwarf_section *section, state_machine_regs.address += ((state_machine_regs.op_index + uladv) / linfo.li_max_ops_per_insn) - * linfo.li_min_insn_length; + * linfo.li_min_insn_length; state_machine_regs.op_index = (state_machine_regs.op_index + uladv) - % linfo.li_max_ops_per_insn; + % linfo.li_max_ops_per_insn; } adv = (op_code % linfo.li_line_range) + linfo.li_line_base; @@ -3044,186 +3199,194 @@ display_debug_lines_decoded (struct dwarf_section *section, is_special_opcode = 1; } else switch (op_code) - { - case DW_LNS_extended_op: - { - unsigned int ext_op_code_len; - unsigned char ext_op_code; - unsigned char *op_code_data = data; - - ext_op_code_len = read_leb128 (op_code_data, &bytes_read, 0); - op_code_data += bytes_read; - - if (ext_op_code_len == 0) - { - warn (_("badly formed extended line op encountered!\n")); - break; - } - ext_op_code_len += bytes_read; - ext_op_code = *op_code_data++; - - switch (ext_op_code) - { - case DW_LNE_end_sequence: - reset_state_machine (linfo.li_default_is_stmt); - break; - case DW_LNE_set_address: - state_machine_regs.address = - byte_get (op_code_data, ext_op_code_len - bytes_read - 1); - state_machine_regs.op_index = 0; - break; - case DW_LNE_define_file: - { - file_table = (File_Entry *) xrealloc - (file_table, (n_files + 1) * sizeof (File_Entry)); - - ++state_machine_regs.last_file_entry; - /* Source file name. */ - file_table[n_files].name = op_code_data; - op_code_data += strlen ((char *) op_code_data) + 1; - /* Directory index. */ - file_table[n_files].directory_index = - read_leb128 (op_code_data, & bytes_read, 0); - op_code_data += bytes_read; - /* Last modification time. */ - file_table[n_files].modification_date = - read_leb128 (op_code_data, & bytes_read, 0); - op_code_data += bytes_read; - /* File length. */ - file_table[n_files].length = - read_leb128 (op_code_data, & bytes_read, 0); - - n_files++; - break; - } - case DW_LNE_set_discriminator: - case DW_LNE_HP_set_sequence: - /* Simply ignored. */ - break; - - default: - printf (_("UNKNOWN (%u): length %d\n"), - ext_op_code, ext_op_code_len - bytes_read); - break; - } - data += ext_op_code_len; - break; - } - case DW_LNS_copy: - break; - - case DW_LNS_advance_pc: - uladv = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - if (linfo.li_max_ops_per_insn == 1) - { - uladv *= linfo.li_min_insn_length; - state_machine_regs.address += uladv; - } - else - { - state_machine_regs.address - += ((state_machine_regs.op_index + uladv) - / linfo.li_max_ops_per_insn) - * linfo.li_min_insn_length; - state_machine_regs.op_index - = (state_machine_regs.op_index + uladv) - % linfo.li_max_ops_per_insn; - } - break; - - case DW_LNS_advance_line: - adv = read_sleb128 (data, & bytes_read); - data += bytes_read; - state_machine_regs.line += adv; - break; - - case DW_LNS_set_file: - adv = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - state_machine_regs.file = adv; - if (file_table[state_machine_regs.file - 1].directory_index == 0) - { - /* If directory index is 0, that means current directory. */ - printf ("\n./%s:[++]\n", - file_table[state_machine_regs.file - 1].name); - } - else - { - /* The directory index starts counting at 1. */ - printf ("\n%s/%s:\n", - directory_table[file_table[state_machine_regs.file - 1].directory_index - 1], - file_table[state_machine_regs.file - 1].name); - } - break; - - case DW_LNS_set_column: - uladv = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - state_machine_regs.column = uladv; - break; - - case DW_LNS_negate_stmt: - adv = state_machine_regs.is_stmt; - adv = ! adv; - state_machine_regs.is_stmt = adv; - break; - - case DW_LNS_set_basic_block: - state_machine_regs.basic_block = 1; - break; - - case DW_LNS_const_add_pc: - uladv = ((255 - linfo.li_opcode_base) / linfo.li_line_range); - if (linfo.li_max_ops_per_insn == 1) - { - uladv *= linfo.li_min_insn_length; - state_machine_regs.address += uladv; - } - else - { - state_machine_regs.address - += ((state_machine_regs.op_index + uladv) - / linfo.li_max_ops_per_insn) - * linfo.li_min_insn_length; - state_machine_regs.op_index - = (state_machine_regs.op_index + uladv) - % linfo.li_max_ops_per_insn; - } - break; - - case DW_LNS_fixed_advance_pc: - uladv = byte_get (data, 2); - data += 2; - state_machine_regs.address += uladv; - state_machine_regs.op_index = 0; - break; - - case DW_LNS_set_prologue_end: - break; - - case DW_LNS_set_epilogue_begin: - break; - - case DW_LNS_set_isa: - uladv = read_leb128 (data, & bytes_read, 0); - data += bytes_read; - printf (_(" Set ISA to %lu\n"), uladv); - break; - - default: - printf (_(" Unknown opcode %d with operands: "), op_code); - - for (i = standard_opcodes[op_code - 1]; i > 0 ; --i) - { - printf ("0x%s%s", dwarf_vmatoa ("x", read_leb128 (data, - &bytes_read, 0)), - i == 1 ? "" : ", "); - data += bytes_read; - } - putchar ('\n'); - break; - } + { + case DW_LNS_extended_op: + { + unsigned int ext_op_code_len; + unsigned char ext_op_code; + unsigned char *op_code_data = data; + + ext_op_code_len = read_uleb128 (op_code_data, &bytes_read, + end_of_sequence); + op_code_data += bytes_read; + + if (ext_op_code_len == 0) + { + warn (_("badly formed extended line op encountered!\n")); + break; + } + ext_op_code_len += bytes_read; + ext_op_code = *op_code_data++; + + switch (ext_op_code) + { + case DW_LNE_end_sequence: + reset_state_machine (linfo.li_default_is_stmt); + break; + case DW_LNE_set_address: + SAFE_BYTE_GET_AND_INC (state_machine_regs.address, + op_code_data, + ext_op_code_len - bytes_read - 1, + end); + state_machine_regs.op_index = 0; + break; + case DW_LNE_define_file: + { + file_table = (File_Entry *) xrealloc + (file_table, (n_files + 1) * sizeof (File_Entry)); + + ++state_machine_regs.last_file_entry; + /* Source file name. */ + file_table[n_files].name = op_code_data; + op_code_data += strlen ((char *) op_code_data) + 1; + /* Directory index. */ + file_table[n_files].directory_index = + read_uleb128 (op_code_data, & bytes_read, + end_of_sequence); + op_code_data += bytes_read; + /* Last modification time. */ + file_table[n_files].modification_date = + read_uleb128 (op_code_data, & bytes_read, + end_of_sequence); + op_code_data += bytes_read; + /* File length. */ + file_table[n_files].length = + read_uleb128 (op_code_data, & bytes_read, + end_of_sequence); + + n_files++; + break; + } + case DW_LNE_set_discriminator: + case DW_LNE_HP_set_sequence: + /* Simply ignored. */ + break; + + default: + printf (_("UNKNOWN (%u): length %d\n"), + ext_op_code, ext_op_code_len - bytes_read); + break; + } + data += ext_op_code_len; + break; + } + case DW_LNS_copy: + break; + + case DW_LNS_advance_pc: + uladv = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + if (linfo.li_max_ops_per_insn == 1) + { + uladv *= linfo.li_min_insn_length; + state_machine_regs.address += uladv; + } + else + { + state_machine_regs.address + += ((state_machine_regs.op_index + uladv) + / linfo.li_max_ops_per_insn) + * linfo.li_min_insn_length; + state_machine_regs.op_index + = (state_machine_regs.op_index + uladv) + % linfo.li_max_ops_per_insn; + } + break; + + case DW_LNS_advance_line: + adv = read_sleb128 (data, & bytes_read, end); + data += bytes_read; + state_machine_regs.line += adv; + break; + + case DW_LNS_set_file: + adv = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + state_machine_regs.file = adv; + + if (file_table == NULL) + printf (_("\n [Use file table entry %d]\n"), state_machine_regs.file - 1); + else if (file_table[state_machine_regs.file - 1].directory_index == 0) + /* If directory index is 0, that means current directory. */ + printf ("\n./%s:[++]\n", + file_table[state_machine_regs.file - 1].name); + else if (directory_table == NULL) + printf (_("\n [Use directory table entry %d]\n"), + file_table[state_machine_regs.file - 1].directory_index - 1); + else + /* The directory index starts counting at 1. */ + printf ("\n%s/%s:\n", + directory_table[file_table[state_machine_regs.file - 1].directory_index - 1], + file_table[state_machine_regs.file - 1].name); + break; + + case DW_LNS_set_column: + uladv = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + state_machine_regs.column = uladv; + break; + + case DW_LNS_negate_stmt: + adv = state_machine_regs.is_stmt; + adv = ! adv; + state_machine_regs.is_stmt = adv; + break; + + case DW_LNS_set_basic_block: + state_machine_regs.basic_block = 1; + break; + + case DW_LNS_const_add_pc: + uladv = ((255 - linfo.li_opcode_base) / linfo.li_line_range); + if (linfo.li_max_ops_per_insn == 1) + { + uladv *= linfo.li_min_insn_length; + state_machine_regs.address += uladv; + } + else + { + state_machine_regs.address + += ((state_machine_regs.op_index + uladv) + / linfo.li_max_ops_per_insn) + * linfo.li_min_insn_length; + state_machine_regs.op_index + = (state_machine_regs.op_index + uladv) + % linfo.li_max_ops_per_insn; + } + break; + + case DW_LNS_fixed_advance_pc: + SAFE_BYTE_GET_AND_INC (uladv, data, 2, end); + state_machine_regs.address += uladv; + state_machine_regs.op_index = 0; + break; + + case DW_LNS_set_prologue_end: + break; + + case DW_LNS_set_epilogue_begin: + break; + + case DW_LNS_set_isa: + uladv = read_uleb128 (data, & bytes_read, end); + data += bytes_read; + printf (_(" Set ISA to %lu\n"), uladv); + break; + + default: + printf (_(" Unknown opcode %d with operands: "), op_code); + + if (standard_opcodes != NULL) + for (i = standard_opcodes[op_code - 1]; i > 0 ; --i) + { + printf ("0x%s%s", dwarf_vmatoa ("x", read_uleb128 (data, + &bytes_read, end)), + i == 1 ? "" : ", "); + data += bytes_read; + } + putchar ('\n'); + break; + } /* Only Special opcodes, DW_LNS_copy and DW_LNE_end_sequence adds a row to the DWARF address/line matrix. */ @@ -3231,9 +3394,16 @@ display_debug_lines_decoded (struct dwarf_section *section, || (op_code == DW_LNS_copy)) { const unsigned int MAX_FILENAME_LENGTH = 35; - char *fileName = (char *)file_table[state_machine_regs.file - 1].name; + char *fileName; char *newFileName = NULL; - size_t fileNameLength = strlen (fileName); + size_t fileNameLength; + + if (file_table) + fileName = (char *) file_table[state_machine_regs.file - 1].name; + else + fileName = ""; + + fileNameLength = strlen (fileName); if ((fileNameLength > MAX_FILENAME_LENGTH) && (!do_wide)) { @@ -3280,10 +3450,21 @@ display_debug_lines_decoded (struct dwarf_section *section, free (newFileName); } } - free (file_table); - file_table = NULL; - free (directory_table); - directory_table = NULL; + + if (file_table) + { + free (file_table); + file_table = NULL; + n_files = 0; + } + + if (directory_table) + { + free (directory_table); + directory_table = NULL; + n_directories = 0; + } + putchar ('\n'); } @@ -3328,9 +3509,29 @@ find_debug_info_for_offset (unsigned long offset) return NULL; } +static const char * +get_gdb_index_symbol_kind_name (gdb_index_symbol_kind kind) +{ + /* See gdb/gdb-index.h. */ + static const char * const kinds[] = + { + N_ ("no info"), + N_ ("type"), + N_ ("variable"), + N_ ("function"), + N_ ("other"), + N_ ("unused5"), + N_ ("unused6"), + N_ ("unused7") + }; + + return _ (kinds[kind]); +} + static int -display_debug_pubnames (struct dwarf_section *section, - void *file ATTRIBUTE_UNUSED) +display_debug_pubnames_worker (struct dwarf_section *section, + void *file ATTRIBUTE_UNUSED, + int is_gnu) { DWARF2_Internal_PubNames names; unsigned char *start = section->start; @@ -3346,16 +3547,14 @@ display_debug_pubnames (struct dwarf_section *section, { unsigned char *data; unsigned long offset; - int offset_size, initial_length_size; + unsigned int offset_size, initial_length_size; data = start; - names.pn_length = byte_get (data, 4); - data += 4; + SAFE_BYTE_GET_AND_INC (names.pn_length, data, 4, end); if (names.pn_length == 0xffffffff) { - names.pn_length = byte_get (data, 8); - data += 8; + SAFE_BYTE_GET_AND_INC (names.pn_length, data, 8, end); offset_size = 8; initial_length_size = 12; } @@ -3365,11 +3564,8 @@ display_debug_pubnames (struct dwarf_section *section, initial_length_size = 4; } - names.pn_version = byte_get (data, 2); - data += 2; - - names.pn_offset = byte_get (data, offset_size); - data += offset_size; + SAFE_BYTE_GET_AND_INC (names.pn_version, data, 2, end); + SAFE_BYTE_GET_AND_INC (names.pn_offset, data, offset_size, end); if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE && num_debug_info_entries > 0 @@ -3377,8 +3573,7 @@ display_debug_pubnames (struct dwarf_section *section, warn (_(".debug_info offset of 0x%lx in %s section does not point to a CU header.\n"), (unsigned long) names.pn_offset, section->name); - names.pn_size = byte_get (data, offset_size); - data += offset_size; + SAFE_BYTE_GET_AND_INC (names.pn_size, data, offset_size, end); start += names.pn_length + initial_length_size; @@ -3404,17 +3599,42 @@ display_debug_pubnames (struct dwarf_section *section, printf (_(" Size of area in .debug_info section: %ld\n"), (long) names.pn_size); - printf (_("\n Offset\tName\n")); + if (is_gnu) + printf (_("\n Offset Kind Name\n")); + else + printf (_("\n Offset\tName\n")); do { - offset = byte_get (data, offset_size); + SAFE_BYTE_GET (offset, data, offset_size, end); if (offset != 0) { data += offset_size; - printf (" %-6lx\t%s\n", offset, data); - data += strlen ((char *) data) + 1; + if (is_gnu) + { + unsigned int kind_data; + gdb_index_symbol_kind kind; + const char *kind_name; + int is_static; + + SAFE_BYTE_GET (kind_data, data, 1, end); + data++; + /* GCC computes the kind as the upper byte in the CU index + word, and then right shifts it by the CU index size. + Left shift KIND to where the gdb-index.h accessor macros + can use it. */ + kind_data <<= GDB_INDEX_CU_BITSIZE; + kind = GDB_INDEX_SYMBOL_KIND_VALUE (kind_data); + kind_name = get_gdb_index_symbol_kind_name (kind); + is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (kind_data); + printf (" %-6lx %s,%-10s %s\n", + offset, is_static ? _("s") : _("g"), + kind_name, data); + } + else + printf (" %-6lx\t%s\n", offset, data); + data += strnlen ((char *) data, end - data) + 1; } } while (offset != 0); @@ -3424,6 +3644,18 @@ display_debug_pubnames (struct dwarf_section *section, return 1; } +static int +display_debug_pubnames (struct dwarf_section *section, void *file) +{ + return display_debug_pubnames_worker (section, file, 0); +} + +static int +display_debug_gnu_pubnames (struct dwarf_section *section, void *file) +{ + return display_debug_pubnames_worker (section, file, 1); +} + static int display_debug_macinfo (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED) @@ -3439,7 +3671,7 @@ display_debug_macinfo (struct dwarf_section *section, while (curr < end) { unsigned int lineno; - const char *string; + const unsigned char *string; op = (enum dwarf_macinfo_record_type) *curr; curr++; @@ -3450,9 +3682,9 @@ display_debug_macinfo (struct dwarf_section *section, { unsigned int filenum; - lineno = read_leb128 (curr, & bytes_read, 0); + lineno = read_uleb128 (curr, & bytes_read, end); curr += bytes_read; - filenum = read_leb128 (curr, & bytes_read, 0); + filenum = read_uleb128 (curr, & bytes_read, end); curr += bytes_read; printf (_(" DW_MACINFO_start_file - lineno: %d filenum: %d\n"), @@ -3465,19 +3697,19 @@ display_debug_macinfo (struct dwarf_section *section, break; case DW_MACINFO_define: - lineno = read_leb128 (curr, & bytes_read, 0); + lineno = read_uleb128 (curr, & bytes_read, end); curr += bytes_read; - string = (char *) curr; - curr += strlen (string) + 1; + string = curr; + curr += strnlen ((char *) string, end - string) + 1; printf (_(" DW_MACINFO_define - lineno : %d macro : %s\n"), lineno, string); break; case DW_MACINFO_undef: - lineno = read_leb128 (curr, & bytes_read, 0); + lineno = read_uleb128 (curr, & bytes_read, end); curr += bytes_read; - string = (char *) curr; - curr += strlen (string) + 1; + string = curr; + curr += strnlen ((char *) string, end - string) + 1; printf (_(" DW_MACINFO_undef - lineno : %d macro : %s\n"), lineno, string); break; @@ -3486,10 +3718,10 @@ display_debug_macinfo (struct dwarf_section *section, { unsigned int constant; - constant = read_leb128 (curr, & bytes_read, 0); + constant = read_uleb128 (curr, & bytes_read, end); curr += bytes_read; - string = (char *) curr; - curr += strlen (string) + 1; + string = curr; + curr += strnlen ((char *) string, end - string) + 1; printf (_(" DW_MACINFO_vendor_ext - constant : %d string : %s\n"), constant, string); } @@ -3505,7 +3737,8 @@ display_debug_macinfo (struct dwarf_section *section, FILEIDX. Return NULL on failure. */ static unsigned char * -get_line_filename_and_dirname (dwarf_vma line_offset, dwarf_vma fileidx, +get_line_filename_and_dirname (dwarf_vma line_offset, + dwarf_vma fileidx, unsigned char **dir_name) { struct dwarf_section *section = &debug_displays [line].section; @@ -3513,6 +3746,7 @@ get_line_filename_and_dirname (dwarf_vma line_offset, dwarf_vma fileidx, unsigned int offset_size, initial_length_size; unsigned int version, opcode_base, bytes_read; dwarf_vma length, diridx; + const unsigned char * end; *dir_name = NULL; if (section->start == NULL @@ -3521,13 +3755,13 @@ get_line_filename_and_dirname (dwarf_vma line_offset, dwarf_vma fileidx, return NULL; hdrptr = section->start + line_offset; - length = byte_get (hdrptr, 4); - hdrptr += 4; + end = section->start + section->size; + + SAFE_BYTE_GET_AND_INC (length, hdrptr, 4, end); if (length == 0xffffffff) { /* This section is 64-bit DWARF 3. */ - length = byte_get (hdrptr, 8); - hdrptr += 8; + SAFE_BYTE_GET_AND_INC (length, hdrptr, 8, end); offset_size = 8; initial_length_size = 12; } @@ -3538,44 +3772,45 @@ get_line_filename_and_dirname (dwarf_vma line_offset, dwarf_vma fileidx, } if (length + initial_length_size > section->size) return NULL; - version = byte_get (hdrptr, 2); - hdrptr += 2; + + SAFE_BYTE_GET_AND_INC (version, hdrptr, 2, end); if (version != 2 && version != 3 && version != 4) return NULL; hdrptr += offset_size + 1;/* Skip prologue_length and min_insn_length. */ if (version >= 4) hdrptr++; /* Skip max_ops_per_insn. */ hdrptr += 3; /* Skip default_is_stmt, line_base, line_range. */ - opcode_base = byte_get (hdrptr, 1); + + SAFE_BYTE_GET_AND_INC (opcode_base, hdrptr, 1, end); if (opcode_base == 0) return NULL; - hdrptr++; + hdrptr += opcode_base - 1; dirtable = hdrptr; /* Skip over dirname table. */ while (*hdrptr != '\0') - hdrptr += strlen ((char *) hdrptr) + 1; + hdrptr += strnlen ((char *) hdrptr, end - hdrptr) + 1; hdrptr++; /* Skip the NUL at the end of the table. */ /* Now skip over preceding filename table entries. */ for (; *hdrptr != '\0' && fileidx > 1; fileidx--) { - hdrptr += strlen ((char *) hdrptr) + 1; - read_leb128 (hdrptr, &bytes_read, 0); + hdrptr += strnlen ((char *) hdrptr, end - hdrptr) + 1; + read_uleb128 (hdrptr, &bytes_read, end); hdrptr += bytes_read; - read_leb128 (hdrptr, &bytes_read, 0); + read_uleb128 (hdrptr, &bytes_read, end); hdrptr += bytes_read; - read_leb128 (hdrptr, &bytes_read, 0); + read_uleb128 (hdrptr, &bytes_read, end); hdrptr += bytes_read; } - if (*hdrptr == '\0') + if (hdrptr == end || *hdrptr == '\0') return NULL; file_name = hdrptr; - hdrptr += strlen ((char *) hdrptr) + 1; - diridx = read_leb128 (hdrptr, &bytes_read, 0); + hdrptr += strnlen ((char *) hdrptr, end - hdrptr) + 1; + diridx = read_uleb128 (hdrptr, &bytes_read, end); if (diridx == 0) return file_name; for (; *dirtable != '\0' && diridx > 1; diridx--) - dirtable += strlen ((char *) dirtable) + 1; + dirtable += strnlen ((char *) dirtable, end - dirtable) + 1; if (*dirtable == '\0') return NULL; *dir_name = dirtable; @@ -3601,13 +3836,11 @@ display_debug_macro (struct dwarf_section *section, { unsigned int lineno, version, flags; unsigned int offset_size = 4; - const char *string; + const unsigned char *string; dwarf_vma line_offset = 0, sec_offset = curr - start, offset; unsigned char **extended_ops = NULL; - version = byte_get (curr, 2); - curr += 2; - + SAFE_BYTE_GET_AND_INC (version, curr, 2, end); if (version != 4) { error (_("Only GNU extension to DWARF 4 of %s is currently supported.\n"), @@ -3615,7 +3848,7 @@ display_debug_macro (struct dwarf_section *section, return 0; } - flags = byte_get (curr++, 1); + SAFE_BYTE_GET_AND_INC (flags, curr, 1, end); if (flags & 1) offset_size = 8; printf (_(" Offset: 0x%lx\n"), @@ -3624,15 +3857,17 @@ display_debug_macro (struct dwarf_section *section, printf (_(" Offset size: %d\n"), offset_size); if (flags & 2) { - line_offset = byte_get (curr, offset_size); - curr += offset_size; + SAFE_BYTE_GET_AND_INC (line_offset, curr, offset_size, end); printf (_(" Offset into .debug_line: 0x%lx\n"), (unsigned long) line_offset); } if (flags & 4) { - unsigned int i, count = byte_get (curr++, 1), op; + unsigned int i, count, op; dwarf_vma nargs, n; + + SAFE_BYTE_GET_AND_INC (count, curr, 1, end); + memset (extended_op_buf, 0, sizeof (extended_op_buf)); extended_ops = extended_op_buf; if (count) @@ -3640,9 +3875,9 @@ display_debug_macro (struct dwarf_section *section, printf (_(" Extension opcode arguments:\n")); for (i = 0; i < count; i++) { - op = byte_get (curr++, 1); + SAFE_BYTE_GET_AND_INC (op, curr, 1, end); extended_ops[op] = curr; - nargs = read_leb128 (curr, &bytes_read, 0); + nargs = read_uleb128 (curr, &bytes_read, end); curr += bytes_read; if (nargs == 0) printf (_(" DW_MACRO_GNU_%02x has no arguments\n"), op); @@ -3651,7 +3886,9 @@ display_debug_macro (struct dwarf_section *section, printf (_(" DW_MACRO_GNU_%02x arguments: "), op); for (n = 0; n < nargs; n++) { - unsigned int form = byte_get (curr++, 1); + unsigned int form; + + SAFE_BYTE_GET_AND_INC (form, curr, 1, end); printf ("%s%s", get_FORM_name (form), n == nargs - 1 ? "\n" : ", "); switch (form) @@ -3693,7 +3930,7 @@ display_debug_macro (struct dwarf_section *section, return 0; } - op = byte_get (curr++, 1); + SAFE_BYTE_GET_AND_INC (op, curr, 1, end); if (op == 0) break; @@ -3704,9 +3941,9 @@ display_debug_macro (struct dwarf_section *section, unsigned int filenum; unsigned char *file_name = NULL, *dir_name = NULL; - lineno = read_leb128 (curr, &bytes_read, 0); + lineno = read_uleb128 (curr, &bytes_read, end); curr += bytes_read; - filenum = read_leb128 (curr, &bytes_read, 0); + filenum = read_uleb128 (curr, &bytes_read, end); curr += bytes_read; if ((flags & 2) == 0) @@ -3731,71 +3968,65 @@ display_debug_macro (struct dwarf_section *section, break; case DW_MACRO_GNU_define: - lineno = read_leb128 (curr, &bytes_read, 0); + lineno = read_uleb128 (curr, &bytes_read, end); curr += bytes_read; - string = (char *) curr; - curr += strlen (string) + 1; + string = curr; + curr += strnlen ((char *) string, end - string) + 1; printf (_(" DW_MACRO_GNU_define - lineno : %d macro : %s\n"), lineno, string); break; case DW_MACRO_GNU_undef: - lineno = read_leb128 (curr, &bytes_read, 0); + lineno = read_uleb128 (curr, &bytes_read, end); curr += bytes_read; - string = (char *) curr; - curr += strlen (string) + 1; + string = curr; + curr += strnlen ((char *) string, end - string) + 1; printf (_(" DW_MACRO_GNU_undef - lineno : %d macro : %s\n"), lineno, string); break; case DW_MACRO_GNU_define_indirect: - lineno = read_leb128 (curr, &bytes_read, 0); + lineno = read_uleb128 (curr, &bytes_read, end); curr += bytes_read; - offset = byte_get (curr, offset_size); - curr += offset_size; + SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end); string = fetch_indirect_string (offset); printf (_(" DW_MACRO_GNU_define_indirect - lineno : %d macro : %s\n"), lineno, string); break; case DW_MACRO_GNU_undef_indirect: - lineno = read_leb128 (curr, &bytes_read, 0); + lineno = read_uleb128 (curr, &bytes_read, end); curr += bytes_read; - offset = byte_get (curr, offset_size); - curr += offset_size; + SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end); string = fetch_indirect_string (offset); printf (_(" DW_MACRO_GNU_undef_indirect - lineno : %d macro : %s\n"), lineno, string); break; case DW_MACRO_GNU_transparent_include: - offset = byte_get (curr, offset_size); - curr += offset_size; + SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end); printf (_(" DW_MACRO_GNU_transparent_include - offset : 0x%lx\n"), (unsigned long) offset); break; case DW_MACRO_GNU_define_indirect_alt: - lineno = read_leb128 (curr, &bytes_read, 0); + lineno = read_uleb128 (curr, &bytes_read, end); curr += bytes_read; - offset = byte_get (curr, offset_size); - curr += offset_size; + SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end); printf (_(" DW_MACRO_GNU_define_indirect_alt - lineno : %d macro offset : 0x%lx\n"), lineno, (unsigned long) offset); break; case DW_MACRO_GNU_undef_indirect_alt: - lineno = read_leb128 (curr, &bytes_read, 0); + lineno = read_uleb128 (curr, &bytes_read, end); curr += bytes_read; - offset = byte_get (curr, offset_size); - curr += offset_size; + SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end); printf (_(" DW_MACRO_GNU_undef_indirect_alt - lineno : %d macro offset : 0x%lx\n"), lineno, (unsigned long) offset); break; case DW_MACRO_GNU_transparent_include_alt: - offset = byte_get (curr, offset_size); - curr += offset_size; + SAFE_BYTE_GET_AND_INC (offset, curr, offset_size, end); printf (_(" DW_MACRO_GNU_transparent_include_alt - offset : 0x%lx\n"), (unsigned long) offset); break; @@ -3811,7 +4042,7 @@ display_debug_macro (struct dwarf_section *section, /* Skip over unhandled opcodes. */ dwarf_vma nargs, n; unsigned char *desc = extended_ops[op]; - nargs = read_leb128 (desc, &bytes_read, 0); + nargs = read_uleb128 (desc, &bytes_read, end); desc += bytes_read; if (nargs == 0) { @@ -3821,9 +4052,12 @@ display_debug_macro (struct dwarf_section *section, printf (_(" DW_MACRO_GNU_%02x -"), op); for (n = 0; n < nargs; n++) { + int val; + + SAFE_BYTE_GET_AND_INC (val, desc, 1, end); curr - = read_and_display_attr_value (0, byte_get (desc++, 1), - curr, 0, 0, offset_size, + = read_and_display_attr_value (0, val, + curr, end, 0, 0, offset_size, version, NULL, 0, NULL, NULL); if (n != nargs - 1) @@ -3924,10 +4158,8 @@ display_loc_list (struct dwarf_section *section, the -1 escape value. Sign extension into the top 32 bits of a 32-bit address will not affect the values that we display since we always show hex values, and always the bottom 32-bits. */ - begin = byte_get_signed (start, pointer_size); - start += pointer_size; - end = byte_get_signed (start, pointer_size); - start += pointer_size; + SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end); + SAFE_BYTE_GET_AND_INC (end, start, pointer_size, section_end); if (begin == 0 && end == 0) { @@ -3952,8 +4184,7 @@ display_loc_list (struct dwarf_section *section, break; } - length = byte_get (start, 2); - start += 2; + SAFE_BYTE_GET_AND_INC (length, start, 2, section_end); if (start + length > section_end) { @@ -4035,8 +4266,7 @@ display_loc_list_dwo (struct dwarf_section *section, break; } - entry_type = byte_get (start, 1); - start++; + SAFE_BYTE_GET_AND_INC (entry_type, start, 1, section_end); switch (entry_type) { case 0: /* A terminating entry. */ @@ -4044,34 +4274,31 @@ display_loc_list_dwo (struct dwarf_section *section, printf (_("\n")); return; case 1: /* A base-address entry. */ - idx = read_leb128 (start, &bytes_read, 0); + idx = read_uleb128 (start, &bytes_read, section_end); start += bytes_read; print_addr_index (idx, 8); printf (" "); printf (_("(base address selection entry)\n")); continue; case 2: /* A start/end entry. */ - idx = read_leb128 (start, &bytes_read, 0); + idx = read_uleb128 (start, &bytes_read, section_end); start += bytes_read; print_addr_index (idx, 8); - idx = read_leb128 (start, &bytes_read, 0); + idx = read_uleb128 (start, &bytes_read, section_end); start += bytes_read; print_addr_index (idx, 8); break; case 3: /* A start/length entry. */ - idx = read_leb128 (start, &bytes_read, 0); + idx = read_uleb128 (start, &bytes_read, section_end); start += bytes_read; print_addr_index (idx, 8); - idx = byte_get (start, 4); - start += 4; + SAFE_BYTE_GET_AND_INC (idx, start, 4, section_end); printf ("%08x ", idx); break; case 4: /* An offset pair entry. */ - idx = byte_get (start, 4); - start += 4; + SAFE_BYTE_GET_AND_INC (idx, start, 4, section_end); printf ("%08x ", idx); - idx = byte_get (start, 4); - start += 4; + SAFE_BYTE_GET_AND_INC (idx, start, 4, section_end); printf ("%08x ", idx); break; default: @@ -4087,9 +4314,7 @@ display_loc_list_dwo (struct dwarf_section *section, break; } - length = byte_get (start, 2); - start += 2; - + SAFE_BYTE_GET_AND_INC (length, start, 2, section_end); if (start + length > section_end) { warn (_("Location list starting at offset 0x%lx is not terminated.\n"), @@ -4208,9 +4433,8 @@ display_debug_loc (struct dwarf_section *section, void *file) if (!seen_first_offset) error (_("No location lists in .debug_info section!\n")); - /* DWARF sections under Mach-O have non-zero addresses. */ if (debug_information [first].num_loc_offsets > 0 - && debug_information [first].loc_offsets [0] != section->address) + && debug_information [first].loc_offsets [0] != 0) warn (_("Location lists in %s section start at 0x%s\n"), section->name, dwarf_vmatoa ("x", debug_information [first].loc_offsets [0])); @@ -4245,8 +4469,7 @@ display_debug_loc (struct dwarf_section *section, void *file) == debug_information [i].loc_offsets [j]) continue; has_frame_base = debug_information [i].have_frame_base [j]; - /* DWARF sections under Mach-O have non-zero addresses. */ - offset = debug_information [i].loc_offsets [j] - section->address; + offset = debug_information [i].loc_offsets [j]; next = section_begin + offset; base_address = debug_information [i].base_address; @@ -4386,18 +4609,15 @@ display_debug_aranges (struct dwarf_section *section, dwarf_vma address; unsigned char address_size; int excess; - int offset_size; - int initial_length_size; + unsigned int offset_size; + unsigned int initial_length_size; hdrptr = start; - arange.ar_length = byte_get (hdrptr, 4); - hdrptr += 4; - + SAFE_BYTE_GET_AND_INC (arange.ar_length, hdrptr, 4, end); if (arange.ar_length == 0xffffffff) { - arange.ar_length = byte_get (hdrptr, 8); - hdrptr += 8; + SAFE_BYTE_GET_AND_INC (arange.ar_length, hdrptr, 8, end); offset_size = 8; initial_length_size = 12; } @@ -4407,11 +4627,8 @@ display_debug_aranges (struct dwarf_section *section, initial_length_size = 4; } - arange.ar_version = byte_get (hdrptr, 2); - hdrptr += 2; - - arange.ar_info_offset = byte_get (hdrptr, offset_size); - hdrptr += offset_size; + SAFE_BYTE_GET_AND_INC (arange.ar_version, hdrptr, 2, end); + SAFE_BYTE_GET_AND_INC (arange.ar_info_offset, hdrptr, offset_size, end); if (num_debug_info_entries != DEBUG_INFO_UNAVAILABLE && num_debug_info_entries > 0 @@ -4419,11 +4636,8 @@ display_debug_aranges (struct dwarf_section *section, warn (_(".debug_info offset of 0x%lx in %s section does not point to a CU header.\n"), (unsigned long) arange.ar_info_offset, section->name); - arange.ar_pointer_size = byte_get (hdrptr, 1); - hdrptr += 1; - - arange.ar_segment_size = byte_get (hdrptr, 1); - hdrptr += 1; + SAFE_BYTE_GET_AND_INC (arange.ar_pointer_size, hdrptr, 1, end); + SAFE_BYTE_GET_AND_INC (arange.ar_segment_size, hdrptr, 1, end); if (arange.ar_version != 2 && arange.ar_version != 3) { @@ -4473,13 +4687,8 @@ display_debug_aranges (struct dwarf_section *section, while (addr_ranges + 2 * address_size <= start) { - address = byte_get (addr_ranges, address_size); - - addr_ranges += address_size; - - length = byte_get (addr_ranges, address_size); - - addr_ranges += address_size; + SAFE_BYTE_GET_AND_INC (address, addr_ranges, address_size, end); + SAFE_BYTE_GET_AND_INC (length, addr_ranges, address_size, end); printf (" "); print_dwarf_vma (address, address_size); @@ -4617,13 +4826,12 @@ display_debug_ranges (struct dwarf_section *section, { unsigned char *start = section->start; unsigned char *last_start = start; - unsigned long bytes; + unsigned long bytes = section->size; unsigned char *section_begin = start; + unsigned char *finish = start + bytes; unsigned int num_range_list, i; struct range_entry *range_entries, *range_entry_fill; - bytes = section->size; - if (bytes == 0) { printf (_("\nThe %s section is empty.\n"), section->name); @@ -4669,8 +4877,7 @@ display_debug_ranges (struct dwarf_section *section, qsort (range_entries, num_range_list, sizeof (*range_entries), range_entry_compar); - /* DWARF sections under Mach-O have non-zero addresses. */ - if (dwarf_check != 0 && range_entries[0].ranges_offset != section->address) + if (dwarf_check != 0 && range_entries[0].ranges_offset != 0) warn (_("Range lists in %s section start at 0x%lx\n"), section->name, range_entries[0].ranges_offset); @@ -4688,8 +4895,7 @@ display_debug_ranges (struct dwarf_section *section, pointer_size = debug_info_p->pointer_size; - /* DWARF sections under Mach-O have non-zero addresses. */ - offset = range_entry->ranges_offset - section->address; + offset = range_entry->ranges_offset; next = section_begin + offset; base_address = debug_info_p->base_address; @@ -4711,7 +4917,7 @@ display_debug_ranges (struct dwarf_section *section, start = next; last_start = next; - while (1) + while (start < finish) { dwarf_vma begin; dwarf_vma end; @@ -4721,10 +4927,10 @@ display_debug_ranges (struct dwarf_section *section, top 32 bits of a 32-bit address will not affect the values that we display since we always show hex values, and always the bottom 32-bits. */ - begin = byte_get_signed (start, pointer_size); - start += pointer_size; - end = byte_get_signed (start, pointer_size); - start += pointer_size; + SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, finish); + if (start >= finish) + break; + SAFE_SIGNED_BYTE_GET_AND_INC (end, start, pointer_size, finish); printf (" %8.8lx ", offset); @@ -4773,8 +4979,8 @@ typedef struct Frame_Chunk char *augmentation; unsigned int code_factor; int data_factor; - unsigned long pc_begin; - unsigned long pc_range; + dwarf_vma pc_begin; + dwarf_vma pc_range; int cfa_reg; int cfa_offset; int ra; @@ -4823,19 +5029,26 @@ frame_need_space (Frame_Chunk *fc, unsigned int reg) static const char *const dwarf_regnames_i386[] = { - "eax", "ecx", "edx", "ebx", - "esp", "ebp", "esi", "edi", - "eip", "eflags", NULL, - "st0", "st1", "st2", "st3", - "st4", "st5", "st6", "st7", - NULL, NULL, - "xmm0", "xmm1", "xmm2", "xmm3", - "xmm4", "xmm5", "xmm6", "xmm7", - "mm0", "mm1", "mm2", "mm3", - "mm4", "mm5", "mm6", "mm7", - "fcw", "fsw", "mxcsr", - "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL, - "tr", "ldtr" + "eax", "ecx", "edx", "ebx", /* 0 - 3 */ + "esp", "ebp", "esi", "edi", /* 4 - 7 */ + "eip", "eflags", NULL, /* 8 - 10 */ + "st0", "st1", "st2", "st3", /* 11 - 14 */ + "st4", "st5", "st6", "st7", /* 15 - 18 */ + NULL, NULL, /* 19 - 20 */ + "xmm0", "xmm1", "xmm2", "xmm3", /* 21 - 24 */ + "xmm4", "xmm5", "xmm6", "xmm7", /* 25 - 28 */ + "mm0", "mm1", "mm2", "mm3", /* 29 - 32 */ + "mm4", "mm5", "mm6", "mm7", /* 33 - 36 */ + "fcw", "fsw", "mxcsr", /* 37 - 39 */ + "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL, /* 40 - 47 */ + "tr", "ldtr", /* 48 - 49 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 50 - 57 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 58 - 65 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 66 - 73 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 74 - 81 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 82 - 89 */ + NULL, NULL, NULL, /* 90 - 92 */ + "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7" /* 93 - 100 */ }; void @@ -4864,7 +5077,17 @@ static const char *const dwarf_regnames_x86_64[] = "es", "cs", "ss", "ds", "fs", "gs", NULL, NULL, "fs.base", "gs.base", NULL, NULL, "tr", "ldtr", - "mxcsr", "fcw", "fsw" + "mxcsr", "fcw", "fsw", + "xmm16", "xmm17", "xmm18", "xmm19", + "xmm20", "xmm21", "xmm22", "xmm23", + "xmm24", "xmm25", "xmm26", "xmm27", + "xmm28", "xmm29", "xmm30", "xmm31", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 83 - 90 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 91 - 98 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 99 - 106 */ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 107 - 114 */ + NULL, NULL, NULL, /* 115 - 117 */ + "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7" }; void @@ -4942,7 +5165,7 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs) printf ("\n"); } - printf ("%0*lx ", eh_addr_size * 2, fc->pc_begin); + print_dwarf_vma (fc->pc_begin, eh_addr_size); if (fc->cfa_exp) strcpy (tmp, "exp"); else @@ -4986,9 +5209,9 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs) printf ("\n"); } -#define GET(N) byte_get (start, N); start += N -#define LEB() read_leb128 (start, & length_return, 0); start += length_return -#define SLEB() read_sleb128 (start, & length_return); start += length_return +#define GET(VAR, N) SAFE_BYTE_GET_AND_INC (VAR, start, N, end); +#define LEB() read_uleb128 (start, & length_return, end); start += length_return +#define SLEB() read_sleb128 (start, & length_return, end); start += length_return static int display_debug_frames (struct dwarf_section *section, @@ -5012,20 +5235,20 @@ display_debug_frames (struct dwarf_section *section, { unsigned char *saved_start; unsigned char *block_end; - unsigned long length; - unsigned long cie_id; + dwarf_vma length; + dwarf_vma cie_id; Frame_Chunk *fc; Frame_Chunk *cie; int need_col_headers = 1; unsigned char *augmentation_data = NULL; unsigned long augmentation_data_len = 0; - int encoded_ptr_size = saved_eh_addr_size; - int offset_size; - int initial_length_size; + unsigned int encoded_ptr_size = saved_eh_addr_size; + unsigned int offset_size; + unsigned int initial_length_size; saved_start = start; - length = byte_get (start, 4); start += 4; + SAFE_BYTE_GET_AND_INC (length, start, 4, end); if (length == 0) { printf ("\n%08lx ZERO terminator\n\n", @@ -5035,8 +5258,7 @@ display_debug_frames (struct dwarf_section *section, if (length == 0xffffffff) { - length = byte_get (start, 8); - start += 8; + SAFE_BYTE_GET_AND_INC (length, start, 8, end); offset_size = 8; initial_length_size = 12; } @@ -5049,13 +5271,16 @@ display_debug_frames (struct dwarf_section *section, block_end = saved_start + length + initial_length_size; if (block_end > end) { - warn ("Invalid length %#08lx in FDE at %#08lx\n", - length, (unsigned long)(saved_start - section_start)); + warn ("Invalid length 0x%s in FDE at %#08lx\n", + dwarf_vmatoa_1 (NULL, length, offset_size), + (unsigned long) (saved_start - section_start)); block_end = end; } - cie_id = byte_get (start, offset_size); start += offset_size; - if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID)) + SAFE_BYTE_GET_AND_INC (cie_id, start, offset_size, end); + + if (is_eh ? (cie_id == 0) : ((offset_size == 4 && cie_id == DW_CIE_ID) + || (offset_size == 8 && cie_id == DW64_CIE_ID))) { int version; @@ -5080,8 +5305,8 @@ display_debug_frames (struct dwarf_section *section, if (version >= 4) { - fc->ptr_size = GET (1); - fc->segment_size = GET (1); + GET (fc->ptr_size, 1); + GET (fc->segment_size, 1); eh_addr_size = fc->ptr_size; } else @@ -5093,7 +5318,7 @@ display_debug_frames (struct dwarf_section *section, fc->data_factor = SLEB (); if (version == 1) { - fc->ra = GET (1); + GET (fc->ra, 1); } else { @@ -5108,15 +5333,18 @@ display_debug_frames (struct dwarf_section *section, } cie = fc; + printf ("\n%08lx ", (unsigned long) (saved_start - section_start)); + print_dwarf_vma (length, fc->ptr_size); + print_dwarf_vma (cie_id, offset_size); + if (do_debug_frames_interp) - printf ("\n%08lx %08lx %08lx CIE \"%s\" cf=%d df=%d ra=%d\n", - (unsigned long)(saved_start - section_start), length, cie_id, - fc->augmentation, fc->code_factor, fc->data_factor, - fc->ra); + { + printf ("CIE \"%s\" cf=%d df=%d ra=%d\n", fc->augmentation, + fc->code_factor, fc->data_factor, fc->ra); + } else { - printf ("\n%08lx %08lx %08lx CIE\n", - (unsigned long)(saved_start - section_start), length, cie_id); + printf ("CIE\n"); printf (" Version: %d\n", version); printf (" Augmentation: \"%s\"\n", fc->augmentation); if (version >= 4) @@ -5183,8 +5411,9 @@ display_debug_frames (struct dwarf_section *section, if (!cie) { - warn ("Invalid CIE pointer %#08lx in FDE at %#08lx\n", - cie_id, (unsigned long)(saved_start - section_start)); + warn ("Invalid CIE pointer 0x%s in FDE at %#08lx\n", + dwarf_vmatoa_1 (NULL, cie_id, offset_size), + (unsigned long) (saved_start - section_start)); fc->ncols = 0; fc->col_type = (short int *) xmalloc (sizeof (short int)); fc->col_offset = (int *) xmalloc (sizeof (int)); @@ -5221,13 +5450,16 @@ display_debug_frames (struct dwarf_section *section, segment_selector = 0; if (fc->segment_size) { - segment_selector = byte_get (start, fc->segment_size); - start += fc->segment_size; + SAFE_BYTE_GET_AND_INC (segment_selector, start, fc->segment_size, end); } fc->pc_begin = get_encoded_value (start, fc->fde_encoding, section); start += encoded_ptr_size; - fc->pc_range = byte_get (start, encoded_ptr_size); - start += encoded_ptr_size; + + /* FIXME: It appears that sometimes the final pc_range value is + encoded in less than encoded_ptr_size bytes. See the x86_64 + run of the "objcopy on compressed debug sections" test for an + example of this. */ + SAFE_BYTE_GET_AND_INC (fc->pc_range, start, encoded_ptr_size, end); if (cie->augmentation[0] == 'z') { @@ -5236,12 +5468,19 @@ display_debug_frames (struct dwarf_section *section, start += augmentation_data_len; } - printf ("\n%08lx %08lx %08lx FDE cie=%08lx pc=", - (unsigned long)(saved_start - section_start), length, cie_id, + printf ("\n%08lx %s %s FDE cie=%08lx pc=", + (unsigned long)(saved_start - section_start), + dwarf_vmatoa_1 (NULL, length, fc->ptr_size), + dwarf_vmatoa_1 (NULL, cie_id, offset_size), (unsigned long)(cie->chunk_start - section_start)); + if (fc->segment_size) printf ("%04lx:", segment_selector); - printf ("%08lx..%08lx\n", fc->pc_begin, fc->pc_begin + fc->pc_range); + + printf ("%s..%s\n", + dwarf_vmatoa_1 (NULL, fc->pc_begin, fc->ptr_size), + dwarf_vmatoa_1 (NULL, fc->pc_begin + fc->pc_range, fc->ptr_size)); + if (! do_debug_frames_interp && augmentation_data_len) { unsigned long i; @@ -5389,7 +5628,8 @@ display_debug_frames (struct dwarf_section *section, { unsigned op, opa; unsigned long ul, reg, roffs; - long l, ofs; + long l; + dwarf_vma ofs; dwarf_vma vma; const char *reg_prefix = ""; @@ -5406,9 +5646,11 @@ display_debug_frames (struct dwarf_section *section, if (do_debug_frames_interp) frame_display_row (fc, &need_col_headers, &max_regs); else - printf (" DW_CFA_advance_loc: %d to %08lx\n", + printf (" DW_CFA_advance_loc: %d to %s\n", opa * fc->code_factor, - fc->pc_begin + opa * fc->code_factor); + dwarf_vmatoa_1 (NULL, + fc->pc_begin + opa * fc->code_factor, + fc->ptr_size)); fc->pc_begin += opa * fc->code_factor; break; @@ -5450,40 +5692,47 @@ display_debug_frames (struct dwarf_section *section, if (do_debug_frames_interp) frame_display_row (fc, &need_col_headers, &max_regs); else - printf (" DW_CFA_set_loc: %08lx\n", (unsigned long)vma); + printf (" DW_CFA_set_loc: %s\n", + dwarf_vmatoa_1 (NULL, vma, fc->ptr_size)); fc->pc_begin = vma; break; case DW_CFA_advance_loc1: - ofs = byte_get (start, 1); start += 1; + SAFE_BYTE_GET_AND_INC (ofs, start, 1, end); if (do_debug_frames_interp) frame_display_row (fc, &need_col_headers, &max_regs); else - printf (" DW_CFA_advance_loc1: %ld to %08lx\n", - ofs * fc->code_factor, - fc->pc_begin + ofs * fc->code_factor); + printf (" DW_CFA_advance_loc1: %ld to %s\n", + (unsigned long) (ofs * fc->code_factor), + dwarf_vmatoa_1 (NULL, + fc->pc_begin + ofs * fc->code_factor, + fc->ptr_size)); fc->pc_begin += ofs * fc->code_factor; break; case DW_CFA_advance_loc2: - ofs = byte_get (start, 2); start += 2; + SAFE_BYTE_GET_AND_INC (ofs, start, 2, end); if (do_debug_frames_interp) frame_display_row (fc, &need_col_headers, &max_regs); else - printf (" DW_CFA_advance_loc2: %ld to %08lx\n", - ofs * fc->code_factor, - fc->pc_begin + ofs * fc->code_factor); + printf (" DW_CFA_advance_loc2: %ld to %s\n", + (unsigned long) (ofs * fc->code_factor), + dwarf_vmatoa_1 (NULL, + fc->pc_begin + ofs * fc->code_factor, + fc->ptr_size)); fc->pc_begin += ofs * fc->code_factor; break; case DW_CFA_advance_loc4: - ofs = byte_get (start, 4); start += 4; + SAFE_BYTE_GET_AND_INC (ofs, start, 4, end); if (do_debug_frames_interp) frame_display_row (fc, &need_col_headers, &max_regs); else - printf (" DW_CFA_advance_loc4: %ld to %08lx\n", - ofs * fc->code_factor, - fc->pc_begin + ofs * fc->code_factor); + printf (" DW_CFA_advance_loc4: %ld to %s\n", + (unsigned long) (ofs * fc->code_factor), + dwarf_vmatoa_1 (NULL, + fc->pc_begin + ofs * fc->code_factor, + fc->ptr_size)); fc->pc_begin += ofs * fc->code_factor; break; @@ -5740,13 +5989,15 @@ display_debug_frames (struct dwarf_section *section, break; case DW_CFA_MIPS_advance_loc8: - ofs = byte_get (start, 8); start += 8; + SAFE_BYTE_GET_AND_INC (ofs, start, 8, end); if (do_debug_frames_interp) frame_display_row (fc, &need_col_headers, &max_regs); else - printf (" DW_CFA_MIPS_advance_loc8: %ld to %08lx\n", - ofs * fc->code_factor, - fc->pc_begin + ofs * fc->code_factor); + printf (" DW_CFA_MIPS_advance_loc8: %ld to %s\n", + (unsigned long) (ofs * fc->code_factor), + dwarf_vmatoa_1 (NULL, + fc->pc_begin + ofs * fc->code_factor, + fc->ptr_size)); fc->pc_begin += ofs * fc->code_factor; break; @@ -5945,38 +6196,9 @@ display_gdb_index (struct dwarf_section *section, else printf ("%c%lu", num_cus > 1 ? '\t' : ' ', (unsigned long) cu); - switch (kind) - { - case GDB_INDEX_SYMBOL_KIND_NONE: - printf (_(" [no symbol information]")); - break; - case GDB_INDEX_SYMBOL_KIND_TYPE: - printf (is_static - ? _(" [static type]") - : _(" [global type]")); - break; - case GDB_INDEX_SYMBOL_KIND_VARIABLE: - printf (is_static - ? _(" [static variable]") - : _(" [global variable]")); - break; - case GDB_INDEX_SYMBOL_KIND_FUNCTION: - printf (is_static - ? _(" [static function]") - : _(" [global function]")); - break; - case GDB_INDEX_SYMBOL_KIND_OTHER: - printf (is_static - ? _(" [static other]") - : _(" [global other]")); - break; - default: - printf (is_static - ? _(" [static unknown: %d]") - : _(" [global unknown: %d]"), - kind); - break; - } + printf (" [%s, %s]", + is_static ? _("static") : _("global"), + get_gdb_index_symbol_kind_name (kind)); if (num_cus > 1) printf ("\n"); } @@ -6600,6 +6822,8 @@ struct dwarf_section_display debug_displays[] = display_debug_lines, &do_debug_lines, 1 }, { { ".debug_pubnames", ".zdebug_pubnames", NULL, NULL, 0, 0, 0 }, display_debug_pubnames, &do_debug_pubnames, 0 }, + { { ".debug_gnu_pubnames", ".zdebug_gnu_pubnames", NULL, NULL, 0, 0, 0 }, + display_debug_gnu_pubnames, &do_debug_pubnames, 0 }, { { ".eh_frame", "", NULL, NULL, 0, 0, 0 }, display_debug_frames, &do_debug_frames, 1 }, { { ".debug_macinfo", ".zdebug_macinfo", NULL, NULL, 0, 0, 0 }, @@ -6612,6 +6836,8 @@ struct dwarf_section_display debug_displays[] = display_debug_loc, &do_debug_loc, 1 }, { { ".debug_pubtypes", ".zdebug_pubtypes", NULL, NULL, 0, 0, 0 }, display_debug_pubnames, &do_debug_pubtypes, 0 }, + { { ".debug_gnu_pubtypes", ".zdebug_gnu_pubtypes", NULL, NULL, 0, 0, 0 }, + display_debug_gnu_pubnames, &do_debug_pubtypes, 0 }, { { ".debug_ranges", ".zdebug_ranges", NULL, NULL, 0, 0, 0 }, display_debug_ranges, &do_debug_ranges, 1 }, { { ".debug_static_func", ".zdebug_static_func", NULL, NULL, 0, 0, 0 },