/* dwarf.c -- display DWARF contents of a BFD binary file
Copyright (C) 2005-2017 Free Software Foundation, Inc.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "sysdep.h"
#include "libiberty.h"
#include "bfd.h"
#include "bfd_stdint.h"
#include "bucomm.h"
#include "elfcomm.h"
#include "elf/common.h"
#include "dwarf2.h"
#include "dwarf.h"
#include "gdb/gdb-index.h"
static const char *regname (unsigned int regno, int row);
static int have_frame_base;
static int need_base_address;
static unsigned int last_pointer_size = 0;
static int warned_about_missing_comp_units = FALSE;
static unsigned int num_debug_info_entries = 0;
static unsigned int alloc_num_debug_info_entries = 0;
static debug_info *debug_information = NULL;
/* Special value for num_debug_info_entries to indicate
that the .debug_info section could not be loaded/parsed. */
#define DEBUG_INFO_UNAVAILABLE (unsigned int) -1
unsigned int eh_addr_size;
int do_debug_info;
int do_debug_abbrevs;
int do_debug_lines;
int do_debug_pubnames;
int do_debug_pubtypes;
int do_debug_aranges;
int do_debug_ranges;
int do_debug_frames;
int do_debug_frames_interp;
int do_debug_macinfo;
int do_debug_str;
int do_debug_loc;
int do_gdb_index;
int do_trace_info;
int do_trace_abbrevs;
int do_trace_aranges;
int do_debug_addr;
int do_debug_cu_index;
int do_wide;
int dwarf_cutoff_level = -1;
unsigned long dwarf_start_die;
int dwarf_check = 0;
/* Collection of CU/TU section sets from .debug_cu_index and .debug_tu_index
sections. For version 1 package files, each set is stored in SHNDX_POOL
as a zero-terminated list of section indexes comprising one set of debug
sections from a .dwo file. */
static unsigned int *shndx_pool = NULL;
static unsigned int shndx_pool_size = 0;
static unsigned int shndx_pool_used = 0;
/* For version 2 package files, each set contains an array of section offsets
and an array of section sizes, giving the offset and size of the
contribution from a CU or TU within one of the debug sections.
When displaying debug info from a package file, we need to use these
tables to locate the corresponding contributions to each section. */
struct cu_tu_set
{
uint64_t signature;
dwarf_vma section_offsets[DW_SECT_MAX];
size_t section_sizes[DW_SECT_MAX];
};
static int cu_count = 0;
static int tu_count = 0;
static struct cu_tu_set *cu_sets = NULL;
static struct cu_tu_set *tu_sets = NULL;
static bfd_boolean load_cu_tu_indexes (void *);
/* Values for do_debug_lines. */
#define FLAG_DEBUG_LINES_RAW 1
#define FLAG_DEBUG_LINES_DECODED 2
static unsigned int
size_of_encoded_value (int encoding)
{
switch (encoding & 0x7)
{
default: /* ??? */
case 0: return eh_addr_size;
case 2: return 2;
case 3: return 4;
case 4: return 8;
}
}
static dwarf_vma
get_encoded_value (unsigned char **pdata,
int encoding,
struct dwarf_section *section,
unsigned char * end)
{
unsigned char * data = * pdata;
unsigned int size = size_of_encoded_value (encoding);
dwarf_vma val;
if (data + size >= end)
{
warn (_("Encoded value extends past end of section\n"));
* pdata = end;
return 0;
}
/* PR 17512: file: 002-829853-0.004. */
if (size > 8)
{
warn (_("Encoded size of %d is too large to read\n"), size);
* pdata = end;
return 0;
}
/* PR 17512: file: 1085-5603-0.004. */
if (size == 0)
{
warn (_("Encoded size of 0 is too small to read\n"));
* pdata = end;
return 0;
}
if (encoding & DW_EH_PE_signed)
val = byte_get_signed (data, size);
else
val = byte_get (data, size);
if ((encoding & 0x70) == DW_EH_PE_pcrel)
val += section->address + (data - section->start);
* pdata = data + size;
return val;
}
#if defined HAVE_LONG_LONG && SIZEOF_LONG_LONG > SIZEOF_LONG
# ifndef __MINGW32__
# define DWARF_VMA_FMT "ll"
# define DWARF_VMA_FMT_LONG "%16.16llx"
# else
# define DWARF_VMA_FMT "I64"
# define DWARF_VMA_FMT_LONG "%016I64x"
# endif
#else
# define DWARF_VMA_FMT "l"
# define DWARF_VMA_FMT_LONG "%16.16lx"
#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_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
for return address. */
static int buf_pos = 0;
static struct dwarf_vmatoa_buf
{
char place[64];
} buf[16];
char *ret;
ret = buf[buf_pos++].place;
buf_pos %= ARRAY_SIZE (buf);
if (num_bytes)
{
/* Printf does not have a way of specifying 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];
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.
For reentrancy, this uses a buffer provided by the caller. */
static const char *
dwarf_vmatoa64 (dwarf_vma hvalue, dwarf_vma lvalue, char *buf,
unsigned int buf_len)
{
int len = 0;
if (hvalue == 0)
snprintf (buf, buf_len, "%" DWARF_VMA_FMT "x", lvalue);
else
{
len = snprintf (buf, buf_len, "%" DWARF_VMA_FMT "x", hvalue);
snprintf (buf + len, buf_len - len,
"%08" DWARF_VMA_FMT "x", lvalue);
}
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,
bfd_boolean sign,
const unsigned char * const end)
{
dwarf_vma result = 0;
unsigned int num_read = 0;
unsigned int shift = 0;
unsigned char byte = 0;
while (data < end)
{
byte = *data++;
num_read++;
result |= ((dwarf_vma) (byte & 0x7f)) << shift;
shift += 7;
if ((byte & 0x80) == 0)
break;
/* PR 17512: file: 0ca183b8.
FIXME: Should we signal this error somehow ? */
if (shift >= sizeof (result) * 8)
break;
}
if (length_return != NULL)
*length_return = num_read;
if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
result |= -((dwarf_vma) 1 << shift);
return result;
}
/* Create a signed version to avoid painful typecasts. */
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 read_leb128 (data, length_return, FALSE, end);
}
#define SAFE_BYTE_GET(VAL, PTR, AMOUNT, END) \
do \
{ \
unsigned int amount = (AMOUNT); \
if (sizeof (VAL) < amount) \
{ \
error (_("internal error: attempt to read %d bytes of data in to %d sized variable"),\
amount, (int) sizeof (VAL)); \
amount = sizeof (VAL); \
} \
if (((PTR) + amount) >= (END)) \
{ \
if ((PTR) < (END)) \
amount = (END) - (PTR); \
else \
amount = 0; \
} \
if (amount == 0 || amount > 8) \
VAL = 0; \
else \
VAL = byte_get ((PTR), amount); \
} \
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)); \
|