Newer
Older
/*
* File dwarf.c - read dwarf2 information from the ELF modules
*
* Copyright (C) 2005, Raphael Junqueira
* Copyright (C) 2006-2010, Eric Pouech
* Copyright (C) 2010, Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Robert Shearman
committed
#define NONAMELESSUNION
#include "config.h"
#include <sys/types.h>
#include <fcntl.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <stdio.h>
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#include <assert.h>
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
Eric Pouech
committed
#include "winuser.h"
#include "ole2.h"
#include "oleauto.h"
#include "image_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_dwarf);
/* FIXME:
* - Functions:
* o unspecified parameters
* o inlined functions
* o Debug{Start|End}Point
#if 0
static void dump(const void* ptr, unsigned len)
{
int i, j;
BYTE msg[128];
static const char hexof[] = "0123456789abcdef";
for (i = 0; i < len; i += 16)
sprintf(msg, "%08x: ", i);
memset(msg + 10, ' ', 3 * 16 + 1 + 16);
for (j = 0; j < min(16, len - i); j++)
{
msg[10 + 3 * j + 0] = hexof[x[i + j] >> 4];
msg[10 + 3 * j + 1] = hexof[x[i + j] & 15];
msg[10 + 3 * j + 2] = ' ';
msg[10 + 3 * 16 + 1 + j] = (x[i + j] >= 0x20 && x[i + j] < 0x7f) ?
x[i + j] : '.';
}
msg[10 + 3 * 16] = ' ';
msg[10 + 3 * 16 + 1 + 16] = '\0';
TRACE("%s\n", msg);
#endif
/**
*
* Main Specs:
* http://www.eagercon.com/dwarf/dwarf3std.htm
* http://www.eagercon.com/dwarf/dwarf-2.0.0.pdf
*
* dwarf2.h: http://www.hakpetzna.com/b/binutils/dwarf2_8h-source.html
*
* example of projects who do dwarf2 parsing:
* http://www.x86-64.org/cgi-bin/cvsweb.cgi/binutils.dead/binutils/readelf.c?rev=1.1.1.2
* http://elis.ugent.be/diota/log/ltrace_elf.c
*/
#include "dwarf.h"
Eric Pouech
committed
typedef struct dwarf2_abbrev_entry_attr_s
{
unsigned long attribute;
unsigned long form;
struct dwarf2_abbrev_entry_attr_s* next;
} dwarf2_abbrev_entry_attr_t;
typedef struct dwarf2_abbrev_entry_s
{
unsigned long entry_code;
unsigned long tag;
unsigned char have_child;
unsigned num_attr;
dwarf2_abbrev_entry_attr_t* attrs;
struct dwarf2_block
{
unsigned size;
const unsigned char* ptr;
};
Eric Pouech
committed
struct attribute
Eric Pouech
committed
unsigned long form;
Eric Pouech
committed
union
{
unsigned long uvalue;

eric pouech
committed
ULONGLONG lluvalue;
Eric Pouech
committed
long svalue;
const char* string;
Eric Pouech
committed
struct dwarf2_block block;
Eric Pouech
committed
} u;
};
typedef struct dwarf2_debug_info_s
{
const dwarf2_abbrev_entry_t*abbrev;
struct symt* symt;
Eric Pouech
committed
const unsigned char** data;
struct vector children;
} dwarf2_debug_info_t;
typedef struct dwarf2_section_s
{
const unsigned char* address;
unsigned size;
DWORD_PTR rva;
enum dwarf2_sections {section_debug, section_string, section_abbrev, section_line, section_max};
typedef struct dwarf2_traverse_context_s
{
const unsigned char* data;
const unsigned char* end_data;
unsigned char word_size;
} dwarf2_traverse_context_t;
/* symt_cache indexes */
#define sc_void 0
#define sc_int1 1
#define sc_int2 2
#define sc_int4 3
#define sc_num 4
typedef struct dwarf2_parse_context_s
{
Eric Pouech
committed
const dwarf2_section_t* sections;
unsigned section;
struct pool pool;
struct module* module;
struct sparse_array abbrev_table;
struct sparse_array debug_info_table;
Peter Oberndorfer
committed
unsigned long load_offset;
Eric Pouech
committed
unsigned long ref_offset;
struct symt* symt_cache[sc_num]; /* void, int1, int2, int4 */
Eric Pouech
committed
/* stored in the dbghelp's module internal structure for later reuse */
struct dwarf2_module_info_s
{
dwarf2_section_t debug_loc;

eric pouech
committed
dwarf2_section_t debug_frame;
dwarf2_section_t eh_frame;
unsigned char word_size;
Eric Pouech
committed
};
#define loc_dwarf2_location_list (loc_user + 0)
#define loc_dwarf2_block (loc_user + 1)
static struct symt* dwarf2_parse_enumeration_type(dwarf2_parse_context_t* ctx, dwarf2_debug_info_t* entry);
Eric Pouech
committed
static unsigned char dwarf2_get_byte(const unsigned char* ptr)
{
return *ptr;
}
static unsigned char dwarf2_parse_byte(dwarf2_traverse_context_t* ctx)
{
Eric Pouech
committed
unsigned char uvalue = dwarf2_get_byte(ctx->data);
ctx->data += 1;
return uvalue;
}
Eric Pouech
committed
static unsigned short dwarf2_get_u2(const unsigned char* ptr)
{
return *(const UINT16*)ptr;
Eric Pouech
committed
}
static unsigned short dwarf2_parse_u2(dwarf2_traverse_context_t* ctx)
{
Eric Pouech
committed
unsigned short uvalue = dwarf2_get_u2(ctx->data);
ctx->data += 2;
return uvalue;
}
Eric Pouech
committed
static unsigned long dwarf2_get_u4(const unsigned char* ptr)
{
return *(const UINT32*)ptr;
Eric Pouech
committed
}
static unsigned long dwarf2_parse_u4(dwarf2_traverse_context_t* ctx)
{
Eric Pouech
committed
unsigned long uvalue = dwarf2_get_u4(ctx->data);
ctx->data += 4;
return uvalue;
}
static DWORD64 dwarf2_get_u8(const unsigned char* ptr)
{
return *(const UINT64*)ptr;
}
static DWORD64 dwarf2_parse_u8(dwarf2_traverse_context_t* ctx)
{
DWORD64 uvalue = dwarf2_get_u8(ctx->data);
ctx->data += 8;
return uvalue;
}
Eric Pouech
committed
static unsigned long dwarf2_get_leb128_as_unsigned(const unsigned char* ptr, const unsigned char** end)
unsigned long ret = 0;
unsigned char byte;
unsigned shift = 0;
Eric Pouech
committed
byte = dwarf2_get_byte(ptr++);
ret |= (byte & 0x7f) << shift;
shift += 7;
Eric Pouech
committed
if (end) *end = ptr;
Eric Pouech
committed
static unsigned long dwarf2_leb128_as_unsigned(dwarf2_traverse_context_t* ctx)
{
unsigned long ret;
assert(ctx);
ret = dwarf2_get_leb128_as_unsigned(ctx->data, &ctx->data);
return ret;
}
static long dwarf2_get_leb128_as_signed(const unsigned char* ptr, const unsigned char** end)
long ret = 0;
unsigned char byte;
unsigned shift = 0;
const unsigned size = sizeof(int) * 8;
Eric Pouech
committed
byte = dwarf2_get_byte(ptr++);
ret |= (byte & 0x7f) << shift;
shift += 7;
Eric Pouech
committed
if (end) *end = ptr;
/* as spec: sign bit of byte is 2nd high order bit (80x40)
* -> 0x80 is used as flag.
*/
if ((shift < size) && (byte & 0x40))
{
ret |= - (1 << shift);
}
return ret;
Eric Pouech
committed
static long dwarf2_leb128_as_signed(dwarf2_traverse_context_t* ctx)
{
long ret = 0;
assert(ctx);
ret = dwarf2_get_leb128_as_signed(ctx->data, &ctx->data);
return ret;
}
static unsigned dwarf2_leb128_length(const dwarf2_traverse_context_t* ctx)
{
unsigned ret;
for (ret = 0; ctx->data[ret] & 0x80; ret++);
return ret + 1;
}
/******************************************************************
* dwarf2_get_addr
*
* Returns an address.
* We assume that in all cases word size from Dwarf matches the size of
* addresses in platform where the exec is compiled.
*/
Eric Pouech
committed
static unsigned long dwarf2_get_addr(const unsigned char* ptr, unsigned word_size)
Eric Pouech
committed
switch (word_size)
Eric Pouech
committed
ret = dwarf2_get_u4(ptr);
case 8:
ret = dwarf2_get_u8(ptr);
break;
Eric Pouech
committed
FIXME("Unsupported Word Size %u\n", word_size);
ret = 0;
}
return ret;
}
Eric Pouech
committed
static unsigned long dwarf2_parse_addr(dwarf2_traverse_context_t* ctx)
{
unsigned long ret = dwarf2_get_addr(ctx->data, ctx->word_size);
ctx->data += ctx->word_size;
return ret;
}
static const char* dwarf2_debug_traverse_ctx(const dwarf2_traverse_context_t* ctx)
{
Eric Pouech
committed
return wine_dbg_sprintf("ctx(%p)", ctx->data);
static const char* dwarf2_debug_ctx(const dwarf2_parse_context_t* ctx)
return wine_dbg_sprintf("ctx(%p,%s)",
ctx, debugstr_w(ctx->module->module.ModuleName));
static const char* dwarf2_debug_di(const dwarf2_debug_info_t* di)
Eric Pouech
committed
return wine_dbg_sprintf("debug_info(abbrev:%p,symt:%p)",
di->abbrev, di->symt);
static dwarf2_abbrev_entry_t*
dwarf2_abbrev_table_find_entry(const struct sparse_array* abbrev_table,
unsigned long entry_code)
assert( NULL != abbrev_table );
return sparse_array_find(abbrev_table, entry_code);
static void dwarf2_parse_abbrev_set(dwarf2_traverse_context_t* abbrev_ctx,
struct sparse_array* abbrev_table,
struct pool* pool)
unsigned long entry_code;
dwarf2_abbrev_entry_t* abbrev_entry;
dwarf2_abbrev_entry_attr_t* new = NULL;
dwarf2_abbrev_entry_attr_t* last = NULL;
unsigned long attribute;
unsigned long form;
assert( NULL != abbrev_ctx );
TRACE("%s, end at %p\n",
dwarf2_debug_traverse_ctx(abbrev_ctx), abbrev_ctx->end_data);
sparse_array_init(abbrev_table, sizeof(dwarf2_abbrev_entry_t), 32);
while (abbrev_ctx->data < abbrev_ctx->end_data)
{
TRACE("now at %s\n", dwarf2_debug_traverse_ctx(abbrev_ctx));
entry_code = dwarf2_leb128_as_unsigned(abbrev_ctx);
TRACE("found entry_code %lu\n", entry_code);
if (!entry_code)
{
TRACE("NULL entry code at %s\n", dwarf2_debug_traverse_ctx(abbrev_ctx));
break;
}
abbrev_entry = sparse_array_add(abbrev_table, entry_code, pool);
assert( NULL != abbrev_entry );
abbrev_entry->entry_code = entry_code;
abbrev_entry->tag = dwarf2_leb128_as_unsigned(abbrev_ctx);
abbrev_entry->have_child = dwarf2_parse_byte(abbrev_ctx);
abbrev_entry->attrs = NULL;
abbrev_entry->num_attr = 0;
TRACE("table:(%p,#%u) entry_code(%lu) tag(0x%lx) have_child(%u) -> %p\n",
abbrev_table, sparse_array_length(abbrev_table),
entry_code, abbrev_entry->tag, abbrev_entry->have_child, abbrev_entry);
last = NULL;
while (1)
{
attribute = dwarf2_leb128_as_unsigned(abbrev_ctx);
form = dwarf2_leb128_as_unsigned(abbrev_ctx);
if (!attribute) break;
new = pool_alloc(pool, sizeof(dwarf2_abbrev_entry_attr_t));
assert(new);
new->attribute = attribute;
new->form = form;
new->next = NULL;
if (abbrev_entry->attrs) last->next = new;
else abbrev_entry->attrs = new;
last = new;
abbrev_entry->num_attr++;
}
TRACE("found %u entries\n", sparse_array_length(abbrev_table));
Eric Pouech
committed
static void dwarf2_swallow_attribute(dwarf2_traverse_context_t* ctx,
const dwarf2_abbrev_entry_attr_t* abbrev_attr)
Eric Pouech
committed
unsigned step;
TRACE("(attr:0x%lx,form:0x%lx)\n", abbrev_attr->attribute, abbrev_attr->form);
Eric Pouech
committed
switch (abbrev_attr->form)
{
Eric Pouech
committed
case DW_FORM_addr: step = ctx->word_size; break;
case DW_FORM_flag:
case DW_FORM_data1:
Eric Pouech
committed
case DW_FORM_ref1: step = 1; break;
Eric Pouech
committed
case DW_FORM_ref2: step = 2; break;
case DW_FORM_data4:
case DW_FORM_ref4:
Eric Pouech
committed
case DW_FORM_strp: step = 4; break;
case DW_FORM_data8:
case DW_FORM_ref8: step = 8; break;
case DW_FORM_sdata:
case DW_FORM_ref_udata:
Eric Pouech
committed
case DW_FORM_udata: step = dwarf2_leb128_length(ctx); break;
case DW_FORM_string: step = strlen((const char*)ctx->data) + 1; break;
case DW_FORM_block: step = dwarf2_leb128_as_unsigned(ctx); break;
case DW_FORM_block1: step = dwarf2_parse_byte(ctx); break;
case DW_FORM_block2: step = dwarf2_parse_u2(ctx); break;
case DW_FORM_block4: step = dwarf2_parse_u4(ctx); break;
default:
FIXME("Unhandled attribute form %lx\n", abbrev_attr->form);
Eric Pouech
committed
return;
Eric Pouech
committed
ctx->data += step;
Eric Pouech
committed
static void dwarf2_fill_attr(const dwarf2_parse_context_t* ctx,
const dwarf2_abbrev_entry_attr_t* abbrev_attr,
const unsigned char* data,
struct attribute* attr)
Eric Pouech
committed
attr->form = abbrev_attr->form;
switch (attr->form)
Eric Pouech
committed
case DW_FORM_ref_addr:
case DW_FORM_addr:
attr->u.uvalue = dwarf2_get_addr(data,
ctx->module->format_info[DFI_DWARF]->u.dwarf2_info->word_size);
Eric Pouech
committed
TRACE("addr<0x%lx>\n", attr->u.uvalue);
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_flag:
attr->u.uvalue = dwarf2_get_byte(data);
TRACE("flag<0x%lx>\n", attr->u.uvalue);
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_data1:
attr->u.uvalue = dwarf2_get_byte(data);
TRACE("data1<%lu>\n", attr->u.uvalue);
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_data2:
attr->u.uvalue = dwarf2_get_u2(data);
TRACE("data2<%lu>\n", attr->u.uvalue);
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_data4:
attr->u.uvalue = dwarf2_get_u4(data);
TRACE("data4<%lu>\n", attr->u.uvalue);
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_data8:

eric pouech
committed
attr->u.lluvalue = dwarf2_get_u8(data);
TRACE("data8<%s>\n", wine_dbgstr_longlong(attr->u.uvalue));
Eric Pouech
committed
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_ref1:
attr->u.uvalue = ctx->ref_offset + dwarf2_get_byte(data);
TRACE("ref1<0x%lx>\n", attr->u.uvalue);
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_ref2:
attr->u.uvalue = ctx->ref_offset + dwarf2_get_u2(data);
TRACE("ref2<0x%lx>\n", attr->u.uvalue);
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_ref4:
attr->u.uvalue = ctx->ref_offset + dwarf2_get_u4(data);
TRACE("ref4<0x%lx>\n", attr->u.uvalue);
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_ref8:
FIXME("Unhandled 64 bit support\n");
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_sdata:
attr->u.svalue = dwarf2_get_leb128_as_signed(data, NULL);
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_ref_udata:
attr->u.uvalue = dwarf2_get_leb128_as_unsigned(data, NULL);
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_udata:
attr->u.uvalue = dwarf2_get_leb128_as_unsigned(data, NULL);
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_string:
attr->u.string = (const char *)data;
TRACE("string<%s>\n", attr->u.string);
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_strp:
{
unsigned long offset = dwarf2_get_u4(data);
attr->u.string = (const char*)ctx->sections[section_string].address + offset;
}
TRACE("strp<%s>\n", attr->u.string);
break;
case DW_FORM_block:
attr->u.block.size = dwarf2_get_leb128_as_unsigned(data, &attr->u.block.ptr);
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_block1:
attr->u.block.size = dwarf2_get_byte(data);
attr->u.block.ptr = data + 1;
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_block2:
attr->u.block.size = dwarf2_get_u2(data);
attr->u.block.ptr = data + 2;
break;
Eric Pouech
committed
Eric Pouech
committed
case DW_FORM_block4:
attr->u.block.size = dwarf2_get_u4(data);
attr->u.block.ptr = data + 4;
break;
Eric Pouech
committed
Eric Pouech
committed
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
default:
FIXME("Unhandled attribute form %lx\n", abbrev_attr->form);
break;
}
}
static BOOL dwarf2_find_attribute(const dwarf2_parse_context_t* ctx,
const dwarf2_debug_info_t* di,
unsigned at, struct attribute* attr)
{
unsigned i, ai = 0;
dwarf2_abbrev_entry_attr_t* abbrev_attr;
dwarf2_abbrev_entry_attr_t* abstract_abbrev_attr;
while (di)
{
abstract_abbrev_attr = NULL;
for (i = 0, abbrev_attr = di->abbrev->attrs; abbrev_attr; i++, abbrev_attr = abbrev_attr->next)
{
if (abbrev_attr->attribute == at)
{
dwarf2_fill_attr(ctx, abbrev_attr, di->data[i], attr);
return TRUE;
}
if (abbrev_attr->attribute == DW_AT_abstract_origin &&
at != DW_AT_sibling)
{
abstract_abbrev_attr = abbrev_attr;
ai = i;
Eric Pouech
committed
}
Eric Pouech
committed
/* do we have an abstract origin debug entry to look into ? */
if (!abstract_abbrev_attr) break;
dwarf2_fill_attr(ctx, abstract_abbrev_attr, di->data[ai], attr);
if (!(di = sparse_array_find(&ctx->debug_info_table, attr->u.uvalue)))
FIXME("Should have found the debug info entry\n");
static void dwarf2_load_one_entry(dwarf2_parse_context_t*, dwarf2_debug_info_t*,
struct symt_compiland*);
static unsigned dwarf2_map_register(int regno)

eric pouech
committed
if (regno == Wine_DW_no_register)

eric pouech
committed
FIXME("What the heck map reg 0x%x\n",regno);
return 0;
}

eric pouech
committed
return dbghelp_current_cpu->map_dwarf_register(regno);
static enum location_error
compute_location(dwarf2_traverse_context_t* ctx, struct location* loc,
HANDLE hproc, const struct location* frame)
DWORD_PTR tmp, stack[64];
unsigned char op;
BOOL piece_found = FALSE;
stack[stk = 0] = 0;
loc->kind = loc_absolute;
loc->reg = Wine_DW_no_register;
while (ctx->data < ctx->end_data)
{
op = dwarf2_parse_byte(ctx);
if (op >= DW_OP_lit0 && op <= DW_OP_lit31)
stack[++stk] = op - DW_OP_lit0;
else if (op >= DW_OP_reg0 && op <= DW_OP_reg31)
/* dbghelp APIs don't know how to cope with this anyway
* (for example 'long long' stored in two registers)
* FIXME: We should tell winedbg how to deal with it (sigh)
*/
if (!piece_found)
{
if (loc->reg != Wine_DW_no_register)
FIXME("Only supporting one reg (%d -> %d)\n",
loc->reg, dwarf2_map_register(op - DW_OP_reg0));
loc->reg = dwarf2_map_register(op - DW_OP_reg0);
}
loc->kind = loc_register;
}
else if (op >= DW_OP_breg0 && op <= DW_OP_breg31)
{
/* dbghelp APIs don't know how to cope with this anyway
* (for example 'long long' stored in two registers)
* FIXME: We should tell winedbg how to deal with it (sigh)
*/
if (!piece_found)
{
if (loc->reg != Wine_DW_no_register)
FIXME("Only supporting one breg (%d -> %d)\n",
loc->reg, dwarf2_map_register(op - DW_OP_breg0));
loc->reg = dwarf2_map_register(op - DW_OP_breg0);
stack[++stk] = dwarf2_leb128_as_signed(ctx);
loc->kind = loc_regrel;
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
}
else switch (op)
{
case DW_OP_nop: break;
case DW_OP_addr: stack[++stk] = dwarf2_parse_addr(ctx); break;
case DW_OP_const1u: stack[++stk] = dwarf2_parse_byte(ctx); break;
case DW_OP_const1s: stack[++stk] = dwarf2_parse_byte(ctx); break;
case DW_OP_const2u: stack[++stk] = dwarf2_parse_u2(ctx); break;
case DW_OP_const2s: stack[++stk] = dwarf2_parse_u2(ctx); break;
case DW_OP_const4u: stack[++stk] = dwarf2_parse_u4(ctx); break;
case DW_OP_const4s: stack[++stk] = dwarf2_parse_u4(ctx); break;
case DW_OP_const8u: stack[++stk] = dwarf2_parse_u8(ctx); break;
case DW_OP_const8s: stack[++stk] = dwarf2_parse_u8(ctx); break;
case DW_OP_constu: stack[++stk] = dwarf2_leb128_as_unsigned(ctx); break;
case DW_OP_consts: stack[++stk] = dwarf2_leb128_as_signed(ctx); break;
case DW_OP_dup: stack[stk + 1] = stack[stk]; stk++; break;
case DW_OP_drop: stk--; break;
case DW_OP_over: stack[stk + 1] = stack[stk - 1]; stk++; break;
case DW_OP_pick: stack[stk + 1] = stack[stk - dwarf2_parse_byte(ctx)]; stk++; break;
case DW_OP_swap: tmp = stack[stk]; stack[stk] = stack[stk-1]; stack[stk-1] = tmp; break;
case DW_OP_rot: tmp = stack[stk]; stack[stk] = stack[stk-1]; stack[stk-1] = stack[stk-2]; stack[stk-2] = tmp; break;
case DW_OP_abs: stack[stk] = labs(stack[stk]); break;
case DW_OP_neg: stack[stk] = -stack[stk]; break;
case DW_OP_not: stack[stk] = ~stack[stk]; break;
case DW_OP_and: stack[stk-1] &= stack[stk]; stk--; break;
case DW_OP_or: stack[stk-1] |= stack[stk]; stk--; break;
case DW_OP_minus: stack[stk-1] -= stack[stk]; stk--; break;
case DW_OP_mul: stack[stk-1] *= stack[stk]; stk--; break;
case DW_OP_plus: stack[stk-1] += stack[stk]; stk--; break;
case DW_OP_xor: stack[stk-1] ^= stack[stk]; stk--; break;
case DW_OP_shl: stack[stk-1] <<= stack[stk]; stk--; break;
case DW_OP_shr: stack[stk-1] >>= stack[stk]; stk--; break;
case DW_OP_plus_uconst: stack[stk] += dwarf2_leb128_as_unsigned(ctx); break;
case DW_OP_shra: stack[stk-1] = stack[stk-1] / (1 << stack[stk]); stk--; break;
case DW_OP_div: stack[stk-1] = stack[stk-1] / stack[stk]; stk--; break;
case DW_OP_mod: stack[stk-1] = stack[stk-1] % stack[stk]; stk--; break;
case DW_OP_ge: stack[stk-1] = (stack[stk-1] >= stack[stk]); stk--; break;
case DW_OP_gt: stack[stk-1] = (stack[stk-1] > stack[stk]); stk--; break;
case DW_OP_le: stack[stk-1] = (stack[stk-1] <= stack[stk]); stk--; break;
case DW_OP_lt: stack[stk-1] = (stack[stk-1] < stack[stk]); stk--; break;
case DW_OP_eq: stack[stk-1] = (stack[stk-1] == stack[stk]); stk--; break;
case DW_OP_ne: stack[stk-1] = (stack[stk-1] != stack[stk]); stk--; break;
case DW_OP_skip: tmp = dwarf2_parse_u2(ctx); ctx->data += tmp; break;
case DW_OP_bra: tmp = dwarf2_parse_u2(ctx); if (!stack[stk--]) ctx->data += tmp; break;
case DW_OP_regx:
tmp = dwarf2_leb128_as_unsigned(ctx);
if (!piece_found)
{
if (loc->reg != Wine_DW_no_register)
FIXME("Only supporting one reg\n");
loc->reg = dwarf2_map_register(tmp);
}
loc->kind = loc_register;
break;
case DW_OP_bregx:
tmp = dwarf2_leb128_as_unsigned(ctx);
if (loc->reg != Wine_DW_no_register)
FIXME("Only supporting one regx\n");
loc->reg = dwarf2_map_register(tmp);
stack[++stk] = dwarf2_leb128_as_signed(ctx);
loc->kind = loc_regrel;
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
case DW_OP_fbreg:
if (loc->reg != Wine_DW_no_register)
FIXME("Only supporting one reg (%d -> -2)\n", loc->reg);
if (frame && frame->kind == loc_register)
{
loc->kind = loc_regrel;
loc->reg = frame->reg;
stack[++stk] = dwarf2_leb128_as_signed(ctx);
}
else if (frame && frame->kind == loc_regrel)
{
loc->kind = loc_regrel;
loc->reg = frame->reg;
stack[++stk] = dwarf2_leb128_as_signed(ctx) + frame->offset;
}
else
{
/* FIXME: this could be later optimized by not recomputing
* this very location expression
*/
loc->kind = loc_dwarf2_block;
stack[++stk] = dwarf2_leb128_as_signed(ctx);
}
break;
case DW_OP_piece:
{
unsigned sz = dwarf2_leb128_as_unsigned(ctx);
WARN("Not handling OP_piece (size=%d)\n", sz);
piece_found = TRUE;
}
break;
case DW_OP_deref:
if (!stk)
{
FIXME("Unexpected empty stack\n");
return loc_err_internal;
}
if (loc->reg != Wine_DW_no_register)
{
WARN("Too complex expression for deref\n");
return loc_err_too_complex;
}
if (hproc)
{
DWORD_PTR addr = stack[stk--];
DWORD_PTR deref;
if (!ReadProcessMemory(hproc, (void*)addr, &deref, sizeof(deref), NULL))
{
WARN("Couldn't read memory at %lx\n", addr);
return loc_err_cant_read;
}
stack[++stk] = deref;
}
else
{
loc->kind = loc_dwarf2_block;
}
break;
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
case DW_OP_deref_size:
if (!stk)
{
FIXME("Unexpected empty stack\n");
return loc_err_internal;
}
if (loc->reg != Wine_DW_no_register)
{
WARN("Too complex expression for deref\n");
return loc_err_too_complex;
}
if (hproc)
{
DWORD_PTR addr = stack[stk--];
BYTE derefsize = dwarf2_parse_byte(ctx);
DWORD64 deref;
if (!ReadProcessMemory(hproc, (void*)addr, &deref, derefsize, NULL))
{
WARN("Couldn't read memory at %lx\n", addr);
return loc_err_cant_read;
}
switch (derefsize)
{
case 1: stack[++stk] = *(unsigned char*)&deref; break;
case 2: stack[++stk] = *(unsigned short*)&deref; break;
case 4: stack[++stk] = *(DWORD*)&deref; break;
case 8: if (ctx->word_size >= derefsize) stack[++stk] = deref; break;
}
}
else
{
loc->kind = loc_dwarf2_block;
}
break;
if (op < DW_OP_lo_user) /* as DW_OP_hi_user is 0xFF, we don't need to test against it */
FIXME("Unhandled attr op: %x\n", op);
/* FIXME else unhandled extension */
return loc_err_internal;
}
}
loc->offset = stack[stk];
return 0;
}
static BOOL dwarf2_compute_location_attr(dwarf2_parse_context_t* ctx,
unsigned long dw,
struct location* loc,
const struct location* frame)
{
Eric Pouech
committed
struct attribute xloc;
if (!dwarf2_find_attribute(ctx, di, dw, &xloc)) return FALSE;
Eric Pouech
committed
switch (xloc.form)
{
case DW_FORM_data1: case DW_FORM_data2:
case DW_FORM_udata: case DW_FORM_sdata:
loc->kind = loc_absolute;
loc->reg = 0;
loc->offset = xloc.u.uvalue;
return TRUE;
case DW_FORM_data4: case DW_FORM_data8:
loc->kind = loc_dwarf2_location_list;
loc->reg = Wine_DW_no_register;
loc->offset = xloc.u.uvalue;
Eric Pouech
committed
return TRUE;

eric pouech
committed
case DW_FORM_block:
case DW_FORM_block1:
case DW_FORM_block2:
case DW_FORM_block4:
break;
default: FIXME("Unsupported yet form %lx\n", xloc.form);
return FALSE;
Eric Pouech
committed
}
Eric Pouech
committed
/* assume we have a block form */
Eric Pouech
committed
if (xloc.u.block.size)
dwarf2_traverse_context_t lctx;
enum location_error err;
Eric Pouech
committed
lctx.data = xloc.u.block.ptr;
lctx.end_data = xloc.u.block.ptr + xloc.u.block.size;
lctx.word_size = ctx->module->format_info[DFI_DWARF]->u.dwarf2_info->word_size;
err = compute_location(&lctx, loc, NULL, frame);
if (err < 0)
{
loc->kind = loc_error;
loc->reg = err;
}
else if (loc->kind == loc_dwarf2_block)
{
unsigned* ptr = pool_alloc(&ctx->module->pool,
sizeof(unsigned) + xloc.u.block.size);
*ptr = xloc.u.block.size;
memcpy(ptr + 1, xloc.u.block.ptr, xloc.u.block.size);
loc->offset = (unsigned long)ptr;
}
Eric Pouech
committed
return TRUE;
static struct symt* dwarf2_lookup_type(dwarf2_parse_context_t* ctx,
const dwarf2_debug_info_t* di)
{
Eric Pouech
committed
struct attribute attr;
Eric Pouech
committed
if (dwarf2_find_attribute(ctx, di, DW_AT_type, &attr))
Eric Pouech
committed
type = sparse_array_find(&ctx->debug_info_table, attr.u.uvalue);
if (!type) FIXME("Unable to find back reference to type %lx\n", attr.u.uvalue);
if (!type->symt)
{
/* load the debug info entity */
dwarf2_load_one_entry(ctx, type, NULL);
}
return type->symt;
}
return NULL;
/******************************************************************
* dwarf2_read_one_debug_info
*
* Loads into memory one debug info entry, and recursively its children (if any)
*/
static BOOL dwarf2_read_one_debug_info(dwarf2_parse_context_t* ctx,
dwarf2_debug_info_t** pdi)
{
const dwarf2_abbrev_entry_t*abbrev;
unsigned long entry_code;
unsigned long offset;
dwarf2_debug_info_t* di;
dwarf2_debug_info_t* child;
dwarf2_debug_info_t** where;
dwarf2_abbrev_entry_attr_t* attr;
unsigned i;
Eric Pouech
committed
struct attribute sibling;
Eric Pouech
committed
offset = traverse->data - ctx->sections[ctx->section].address;
entry_code = dwarf2_leb128_as_unsigned(traverse);
TRACE("found entry_code %lu at 0x%lx\n", entry_code, offset);
if (!entry_code)
{
*pdi = NULL;
return TRUE;
}
abbrev = dwarf2_abbrev_table_find_entry(&ctx->abbrev_table, entry_code);
if (!abbrev)
{
WARN("Cannot find abbrev entry for %lu at 0x%lx\n", entry_code, offset);
return FALSE;
}
di = sparse_array_add(&ctx->debug_info_table, offset, &ctx->pool);
if (!di) return FALSE;
di->abbrev = abbrev;
di->symt = NULL;
if (abbrev->num_attr)
{
Eric Pouech
committed
di->data = pool_alloc(&ctx->pool, abbrev->num_attr * sizeof(const char*));
for (i = 0, attr = abbrev->attrs; attr; i++, attr = attr->next)
{
Eric Pouech
committed
di->data[i] = traverse->data;
dwarf2_swallow_attribute(traverse, attr);
Eric Pouech
committed
else di->data = NULL;
if (abbrev->have_child)
{
vector_init(&di->children, sizeof(dwarf2_debug_info_t*), 16);
while (traverse->data < traverse->end_data)
if (!dwarf2_read_one_debug_info(ctx, traverse, &child)) return FALSE;
if (!child) break;
where = vector_add(&di->children, &ctx->pool);
if (!where) return FALSE;
*where = child;