dbghelp: Added struct location to help computing a location.
Make use of it in dwarf.c to handle correctly variable location computation. Split code to handle both location with parse time computation (current code) and yet to come run-time computation
This commit is contained in:
parent
848f8c41c0
commit
d5c4e55d36
|
@ -113,6 +113,27 @@ extern unsigned dbghelp_options;
|
||||||
/* some more Wine extensions */
|
/* some more Wine extensions */
|
||||||
#define SYMOPT_WINE_WITH_ELF_MODULES 0x40000000
|
#define SYMOPT_WINE_WITH_ELF_MODULES 0x40000000
|
||||||
|
|
||||||
|
enum location_kind {loc_error, /* reg is the error code */
|
||||||
|
loc_absolute, /* offset is the location */
|
||||||
|
loc_register, /* reg is the location */
|
||||||
|
loc_regrel, /* [reg+offset] is the location */
|
||||||
|
loc_user, /* value is debug information dependent,
|
||||||
|
reg & offset can be used ad libidem */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum location_error {loc_err_internal = -1, /* internal while computing */
|
||||||
|
loc_err_too_complex = -2, /* couldn't compute location (even at runtime) */
|
||||||
|
loc_err_out_of_scope = -3, /* variable isn't available at current address */
|
||||||
|
loc_err_cant_read = -4, /* couldn't read memory at given address */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct location
|
||||||
|
{
|
||||||
|
unsigned kind : 8,
|
||||||
|
reg;
|
||||||
|
unsigned long offset;
|
||||||
|
};
|
||||||
|
|
||||||
struct symt
|
struct symt
|
||||||
{
|
{
|
||||||
enum SymTagEnum tag;
|
enum SymTagEnum tag;
|
||||||
|
|
|
@ -185,6 +185,9 @@ struct dwarf2_module_info_s
|
||||||
dwarf2_section_t debug_loc;
|
dwarf2_section_t debug_loc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define loc_dwarf2_location_list (loc_user + 0)
|
||||||
|
#define loc_dwarf2_block (loc_user + 1)
|
||||||
|
|
||||||
/* forward declarations */
|
/* forward declarations */
|
||||||
static struct symt* dwarf2_parse_enumeration_type(dwarf2_parse_context_t* ctx, dwarf2_debug_info_t* entry);
|
static struct symt* dwarf2_parse_enumeration_type(dwarf2_parse_context_t* ctx, dwarf2_debug_info_t* entry);
|
||||||
|
|
||||||
|
@ -573,121 +576,196 @@ static void dwarf2_load_one_entry(dwarf2_parse_context_t*, dwarf2_debug_info_t*,
|
||||||
struct symt_compiland*);
|
struct symt_compiland*);
|
||||||
|
|
||||||
#define Wine_DW_no_register 0x7FFFFFFF
|
#define Wine_DW_no_register 0x7FFFFFFF
|
||||||
#define Wine_DW_frame_register 0x7FFFFFFE
|
|
||||||
#define Wine_DW_register_deref 0x80000000
|
|
||||||
|
|
||||||
static BOOL dwarf2_compute_location(dwarf2_parse_context_t* ctx,
|
static unsigned dwarf2_map_register(int regno)
|
||||||
dwarf2_debug_info_t* di,
|
|
||||||
unsigned long dw,
|
|
||||||
unsigned long* offset, int* in_register)
|
|
||||||
{
|
{
|
||||||
unsigned long loc[64];
|
unsigned reg;
|
||||||
|
|
||||||
|
switch (regno)
|
||||||
|
{
|
||||||
|
case Wine_DW_no_register: FIXME("What the heck map reg 0x%x\n",regno); reg = 0; break;
|
||||||
|
case 0: reg = CV_REG_EAX; break;
|
||||||
|
case 1: reg = CV_REG_ECX; break;
|
||||||
|
case 2: reg = CV_REG_EDX; break;
|
||||||
|
case 3: reg = CV_REG_EBX; break;
|
||||||
|
case 4: reg = CV_REG_ESP; break;
|
||||||
|
case 5: reg = CV_REG_EBP; break;
|
||||||
|
case 6: reg = CV_REG_ESI; break;
|
||||||
|
case 7: reg = CV_REG_EDI; break;
|
||||||
|
case 8: reg = CV_REG_EIP; break;
|
||||||
|
case 9: reg = CV_REG_EFLAGS; break;
|
||||||
|
case 10: reg = CV_REG_CS; break;
|
||||||
|
case 11: reg = CV_REG_SS; break;
|
||||||
|
case 12: reg = CV_REG_DS; break;
|
||||||
|
case 13: reg = CV_REG_ES; break;
|
||||||
|
case 14: reg = CV_REG_FS; break;
|
||||||
|
case 15: reg = CV_REG_GS; break;
|
||||||
|
case 16: case 17: case 18: case 19:
|
||||||
|
case 20: case 21: case 22: case 23:
|
||||||
|
reg = CV_REG_ST0 + regno - 16; break;
|
||||||
|
case 24: reg = CV_REG_CTRL; break;
|
||||||
|
case 25: reg = CV_REG_STAT; break;
|
||||||
|
case 26: reg = CV_REG_TAG; break;
|
||||||
|
/*
|
||||||
|
reg: fiseg 27
|
||||||
|
reg: fioff 28
|
||||||
|
reg: foseg 29
|
||||||
|
reg: fooff 30
|
||||||
|
reg: fop 31
|
||||||
|
*/
|
||||||
|
case 32: case 33: case 34: case 35:
|
||||||
|
case 36: case 37: case 38: case 39:
|
||||||
|
reg = CV_REG_XMM0 + regno - 32; break;
|
||||||
|
case 40: reg = CV_REG_MXCSR; break;
|
||||||
|
default:
|
||||||
|
FIXME("Don't know how to map register %d\n", regno);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL compute_location(dwarf2_traverse_context_t* ctx, struct location* loc,
|
||||||
|
const struct location* frame)
|
||||||
|
{
|
||||||
|
unsigned long stack[64];
|
||||||
unsigned stk;
|
unsigned stk;
|
||||||
|
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);
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
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] = (long)(signed char)dwarf2_parse_byte(ctx); break;
|
||||||
|
case DW_OP_const2u: stack[++stk] = dwarf2_parse_u2(ctx); break;
|
||||||
|
case DW_OP_const2s: stack[++stk] = (long)(short)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_constu: stack[++stk] = dwarf2_leb128_as_unsigned(ctx); break;
|
||||||
|
case DW_OP_consts: stack[++stk] = dwarf2_leb128_as_signed(ctx); break;
|
||||||
|
case DW_OP_plus_uconst:
|
||||||
|
stack[stk] += dwarf2_leb128_as_unsigned(ctx); break;
|
||||||
|
case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: case DW_OP_reg3:
|
||||||
|
case DW_OP_reg4: case DW_OP_reg5: case DW_OP_reg6: case DW_OP_reg7:
|
||||||
|
case DW_OP_reg8: case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11:
|
||||||
|
case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: case DW_OP_reg15:
|
||||||
|
case DW_OP_reg16: case DW_OP_reg17: case DW_OP_reg18: case DW_OP_reg19:
|
||||||
|
case DW_OP_reg20: case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23:
|
||||||
|
case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: case DW_OP_reg27:
|
||||||
|
case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31:
|
||||||
|
case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: case DW_OP_breg3:
|
||||||
|
case DW_OP_breg4: case DW_OP_breg5: case DW_OP_breg6: case DW_OP_breg7:
|
||||||
|
case DW_OP_breg8: case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11:
|
||||||
|
case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: case DW_OP_breg15:
|
||||||
|
case DW_OP_breg16: case DW_OP_breg17: case DW_OP_breg18: case DW_OP_breg19:
|
||||||
|
case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23:
|
||||||
|
case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27:
|
||||||
|
case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case 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 || (op - DW_OP_reg0 != loc->reg + 1))
|
||||||
|
{
|
||||||
|
if (loc->reg != Wine_DW_no_register)
|
||||||
|
FIXME("Only supporting one reg (%d -> %d)\n",
|
||||||
|
loc->reg, op - DW_OP_reg0);
|
||||||
|
loc->reg = dwarf2_map_register(op - DW_OP_reg0);
|
||||||
|
}
|
||||||
|
if (op >= DW_OP_breg0 && op <= DW_OP_breg31)
|
||||||
|
{
|
||||||
|
stack[++stk] = dwarf2_leb128_as_signed(ctx);
|
||||||
|
loc->kind = loc_regrel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
loc->kind = loc_register;
|
||||||
|
break;
|
||||||
|
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 directly (size=%d)\n", sz);
|
||||||
|
piece_found = TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
FIXME("Unhandled attr op: %x\n", op);
|
||||||
|
loc->offset = 0;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loc->offset = stack[stk];
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL dwarf2_compute_location_attr(dwarf2_parse_context_t* ctx,
|
||||||
|
dwarf2_debug_info_t* di,
|
||||||
|
unsigned long dw,
|
||||||
|
struct location* loc,
|
||||||
|
const struct location* frame)
|
||||||
|
{
|
||||||
struct attribute xloc;
|
struct attribute xloc;
|
||||||
|
|
||||||
if (!dwarf2_find_attribute(ctx, di, dw, &xloc)) return FALSE;
|
if (!dwarf2_find_attribute(ctx, di, dw, &xloc)) return FALSE;
|
||||||
|
|
||||||
if (in_register) *in_register = Wine_DW_no_register;
|
|
||||||
|
|
||||||
switch (xloc.form)
|
switch (xloc.form)
|
||||||
{
|
{
|
||||||
case DW_FORM_data1: case DW_FORM_data2:
|
case DW_FORM_data1: case DW_FORM_data2:
|
||||||
case DW_FORM_data4: case DW_FORM_data8:
|
|
||||||
case DW_FORM_udata: case DW_FORM_sdata:
|
case DW_FORM_udata: case DW_FORM_sdata:
|
||||||
/* we've got a constant */
|
loc->kind = loc_absolute;
|
||||||
*offset = xloc.u.uvalue;
|
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;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* assume we have a block form */
|
/* assume we have a block form */
|
||||||
loc[stk = 0] = 0;
|
|
||||||
|
|
||||||
if (xloc.u.block.size)
|
if (xloc.u.block.size)
|
||||||
{
|
{
|
||||||
dwarf2_traverse_context_t lctx;
|
dwarf2_traverse_context_t lctx;
|
||||||
unsigned char op;
|
|
||||||
BOOL piece_found = FALSE;
|
|
||||||
|
|
||||||
lctx.data = xloc.u.block.ptr;
|
lctx.data = xloc.u.block.ptr;
|
||||||
lctx.end_data = xloc.u.block.ptr + xloc.u.block.size;
|
lctx.end_data = xloc.u.block.ptr + xloc.u.block.size;
|
||||||
lctx.word_size = ctx->word_size;
|
lctx.word_size = ctx->word_size;
|
||||||
|
|
||||||
while (lctx.data < lctx.end_data)
|
compute_location(&lctx, loc, frame);
|
||||||
{
|
|
||||||
op = dwarf2_parse_byte(&lctx);
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case DW_OP_addr: loc[++stk] = dwarf2_parse_addr(&lctx); break;
|
|
||||||
case DW_OP_const1u: loc[++stk] = dwarf2_parse_byte(&lctx); break;
|
|
||||||
case DW_OP_const1s: loc[++stk] = (long)(signed char)dwarf2_parse_byte(&lctx); break;
|
|
||||||
case DW_OP_const2u: loc[++stk] = dwarf2_parse_u2(&lctx); break;
|
|
||||||
case DW_OP_const2s: loc[++stk] = (long)(short)dwarf2_parse_u2(&lctx); break;
|
|
||||||
case DW_OP_const4u: loc[++stk] = dwarf2_parse_u4(&lctx); break;
|
|
||||||
case DW_OP_const4s: loc[++stk] = dwarf2_parse_u4(&lctx); break;
|
|
||||||
case DW_OP_constu: loc[++stk] = dwarf2_leb128_as_unsigned(&lctx); break;
|
|
||||||
case DW_OP_consts: loc[++stk] = dwarf2_leb128_as_signed(&lctx); break;
|
|
||||||
case DW_OP_plus_uconst:
|
|
||||||
loc[stk] += dwarf2_leb128_as_unsigned(&lctx); break;
|
|
||||||
case DW_OP_reg0: case DW_OP_reg1: case DW_OP_reg2: case DW_OP_reg3:
|
|
||||||
case DW_OP_reg4: case DW_OP_reg5: case DW_OP_reg6: case DW_OP_reg7:
|
|
||||||
case DW_OP_reg8: case DW_OP_reg9: case DW_OP_reg10: case DW_OP_reg11:
|
|
||||||
case DW_OP_reg12: case DW_OP_reg13: case DW_OP_reg14: case DW_OP_reg15:
|
|
||||||
case DW_OP_reg16: case DW_OP_reg17: case DW_OP_reg18: case DW_OP_reg19:
|
|
||||||
case DW_OP_reg20: case DW_OP_reg21: case DW_OP_reg22: case DW_OP_reg23:
|
|
||||||
case DW_OP_reg24: case DW_OP_reg25: case DW_OP_reg26: case DW_OP_reg27:
|
|
||||||
case DW_OP_reg28: case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31:
|
|
||||||
case DW_OP_breg0: case DW_OP_breg1: case DW_OP_breg2: case DW_OP_breg3:
|
|
||||||
case DW_OP_breg4: case DW_OP_breg5: case DW_OP_breg6: case DW_OP_breg7:
|
|
||||||
case DW_OP_breg8: case DW_OP_breg9: case DW_OP_breg10: case DW_OP_breg11:
|
|
||||||
case DW_OP_breg12: case DW_OP_breg13: case DW_OP_breg14: case DW_OP_breg15:
|
|
||||||
case DW_OP_breg16: case DW_OP_breg17: case DW_OP_breg18: case DW_OP_breg19:
|
|
||||||
case DW_OP_breg20: case DW_OP_breg21: case DW_OP_breg22: case DW_OP_breg23:
|
|
||||||
case DW_OP_breg24: case DW_OP_breg25: case DW_OP_breg26: case DW_OP_breg27:
|
|
||||||
case DW_OP_breg28: case DW_OP_breg29: case DW_OP_breg30: case DW_OP_breg31:
|
|
||||||
if (in_register)
|
|
||||||
{
|
|
||||||
/* 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 || (op - DW_OP_reg0 != *in_register + 1))
|
|
||||||
{
|
|
||||||
if (*in_register != Wine_DW_no_register)
|
|
||||||
FIXME("Only supporting one reg (%d -> %d)\n",
|
|
||||||
*in_register, op - DW_OP_reg0);
|
|
||||||
*in_register = op - DW_OP_reg0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else FIXME("Found register, while not expecting it\n");
|
|
||||||
if (op >= DW_OP_breg0 && op <= DW_OP_breg31)
|
|
||||||
{
|
|
||||||
loc[++stk] = dwarf2_leb128_as_signed(&lctx);
|
|
||||||
if (in_register) *in_register |= Wine_DW_register_deref;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DW_OP_fbreg:
|
|
||||||
if (in_register)
|
|
||||||
{
|
|
||||||
if (*in_register != Wine_DW_no_register)
|
|
||||||
FIXME("Only supporting one reg (%d -> -2)\n", *in_register);
|
|
||||||
*in_register = Wine_DW_frame_register | Wine_DW_register_deref;
|
|
||||||
}
|
|
||||||
else FIXME("Found register, while not expecting it\n");
|
|
||||||
loc[++stk] = dwarf2_leb128_as_signed(&lctx);
|
|
||||||
break;
|
|
||||||
case DW_OP_piece:
|
|
||||||
{
|
|
||||||
unsigned sz = dwarf2_leb128_as_unsigned(&lctx);
|
|
||||||
WARN("Not handling OP_piece directly (size=%d)\n", sz);
|
|
||||||
piece_found = TRUE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
FIXME("Unhandled attr op: %x\n", op);
|
|
||||||
return loc[stk];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
*offset = loc[stk];
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -956,9 +1034,9 @@ static void dwarf2_parse_udt_member(dwarf2_parse_context_t* ctx,
|
||||||
{
|
{
|
||||||
struct symt* elt_type;
|
struct symt* elt_type;
|
||||||
struct attribute name;
|
struct attribute name;
|
||||||
unsigned long offset = 0;
|
|
||||||
struct attribute bit_size;
|
struct attribute bit_size;
|
||||||
struct attribute bit_offset;
|
struct attribute bit_offset;
|
||||||
|
struct location loc;
|
||||||
|
|
||||||
assert(parent);
|
assert(parent);
|
||||||
|
|
||||||
|
@ -966,8 +1044,19 @@ static void dwarf2_parse_udt_member(dwarf2_parse_context_t* ctx,
|
||||||
|
|
||||||
dwarf2_find_name(ctx, di, &name, "udt_member");
|
dwarf2_find_name(ctx, di, &name, "udt_member");
|
||||||
elt_type = dwarf2_lookup_type(ctx, di);
|
elt_type = dwarf2_lookup_type(ctx, di);
|
||||||
if (dwarf2_compute_location(ctx, di, DW_AT_data_member_location, &offset, NULL))
|
if (dwarf2_compute_location_attr(ctx, di, DW_AT_data_member_location, &loc, NULL))
|
||||||
TRACE("found member_location at %s -> %lu\n", dwarf2_debug_ctx(ctx), offset);
|
{
|
||||||
|
if (loc.kind != loc_absolute)
|
||||||
|
{
|
||||||
|
FIXME("Found register, while not expecting it\n");
|
||||||
|
loc.offset = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
TRACE("found member_location at %s -> %lu\n",
|
||||||
|
dwarf2_debug_ctx(ctx), loc.offset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
loc.offset = 0;
|
||||||
if (!dwarf2_find_attribute(ctx, di, DW_AT_bit_size, &bit_size)) bit_size.u.uvalue = 0;
|
if (!dwarf2_find_attribute(ctx, di, DW_AT_bit_size, &bit_size)) bit_size.u.uvalue = 0;
|
||||||
if (dwarf2_find_attribute(ctx, di, DW_AT_bit_offset, &bit_offset))
|
if (dwarf2_find_attribute(ctx, di, DW_AT_bit_offset, &bit_offset))
|
||||||
{
|
{
|
||||||
|
@ -984,7 +1073,8 @@ static void dwarf2_parse_udt_member(dwarf2_parse_context_t* ctx,
|
||||||
}
|
}
|
||||||
else bit_offset.u.uvalue = 0;
|
else bit_offset.u.uvalue = 0;
|
||||||
symt_add_udt_element(ctx->module, parent, name.u.string, elt_type,
|
symt_add_udt_element(ctx->module, parent, name.u.string, elt_type,
|
||||||
(offset << 3) + bit_offset.u.uvalue, bit_size.u.uvalue);
|
(loc.offset << 3) + bit_offset.u.uvalue,
|
||||||
|
bit_size.u.uvalue);
|
||||||
|
|
||||||
if (di->abbrev->have_child) FIXME("Unsupported children\n");
|
if (di->abbrev->have_child) FIXME("Unsupported children\n");
|
||||||
}
|
}
|
||||||
|
@ -1094,63 +1184,13 @@ static struct symt* dwarf2_parse_enumeration_type(dwarf2_parse_context_t* ctx,
|
||||||
return di->symt;
|
return di->symt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned dwarf2_map_register(int regno)
|
|
||||||
{
|
|
||||||
unsigned reg;
|
|
||||||
|
|
||||||
switch (regno)
|
|
||||||
{
|
|
||||||
case Wine_DW_no_register: FIXME("What the heck map reg 0x%x\n",regno); reg = 0; break;
|
|
||||||
/* FIXME: this is a dirty hack */
|
|
||||||
case Wine_DW_frame_register: reg = 0; break;
|
|
||||||
case 0: reg = CV_REG_EAX; break;
|
|
||||||
case 1: reg = CV_REG_ECX; break;
|
|
||||||
case 2: reg = CV_REG_EDX; break;
|
|
||||||
case 3: reg = CV_REG_EBX; break;
|
|
||||||
case 4: reg = CV_REG_ESP; break;
|
|
||||||
case 5: reg = CV_REG_EBP; break;
|
|
||||||
case 6: reg = CV_REG_ESI; break;
|
|
||||||
case 7: reg = CV_REG_EDI; break;
|
|
||||||
case 8: reg = CV_REG_EIP; break;
|
|
||||||
case 9: reg = CV_REG_EFLAGS; break;
|
|
||||||
case 10: reg = CV_REG_CS; break;
|
|
||||||
case 11: reg = CV_REG_SS; break;
|
|
||||||
case 12: reg = CV_REG_DS; break;
|
|
||||||
case 13: reg = CV_REG_ES; break;
|
|
||||||
case 14: reg = CV_REG_FS; break;
|
|
||||||
case 15: reg = CV_REG_GS; break;
|
|
||||||
case 16: case 17: case 18: case 19:
|
|
||||||
case 20: case 21: case 22: case 23:
|
|
||||||
reg = CV_REG_ST0 + regno - 16; break;
|
|
||||||
case 24: reg = CV_REG_CTRL; break;
|
|
||||||
case 25: reg = CV_REG_STAT; break;
|
|
||||||
case 26: reg = CV_REG_TAG; break;
|
|
||||||
/*
|
|
||||||
reg: fiseg 27
|
|
||||||
reg: fioff 28
|
|
||||||
reg: foseg 29
|
|
||||||
reg: fooff 30
|
|
||||||
reg: fop 31
|
|
||||||
*/
|
|
||||||
case 32: case 33: case 34: case 35:
|
|
||||||
case 36: case 37: case 38: case 39:
|
|
||||||
reg = CV_REG_XMM0 + regno - 32; break;
|
|
||||||
case 40: reg = CV_REG_MXCSR; break;
|
|
||||||
default:
|
|
||||||
FIXME("Don't know how to map register %d\n", regno);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* structure used to pass information around when parsing a subprogram */
|
/* structure used to pass information around when parsing a subprogram */
|
||||||
typedef struct dwarf2_subprogram_s
|
typedef struct dwarf2_subprogram_s
|
||||||
{
|
{
|
||||||
dwarf2_parse_context_t* ctx;
|
dwarf2_parse_context_t* ctx;
|
||||||
struct symt_compiland* compiland;
|
struct symt_compiland* compiland;
|
||||||
struct symt_function* func;
|
struct symt_function* func;
|
||||||
unsigned long frame_offset;
|
struct location frame;
|
||||||
int frame_reg;
|
|
||||||
} dwarf2_subprogram_t;
|
} dwarf2_subprogram_t;
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
|
@ -1164,47 +1204,60 @@ static void dwarf2_parse_variable(dwarf2_subprogram_t* subpgm,
|
||||||
{
|
{
|
||||||
struct symt* param_type;
|
struct symt* param_type;
|
||||||
struct attribute name, value;
|
struct attribute name, value;
|
||||||
unsigned long offset;
|
struct location loc;
|
||||||
int in_reg;
|
|
||||||
BOOL is_pmt = di->abbrev->tag == DW_TAG_formal_parameter;
|
BOOL is_pmt = di->abbrev->tag == DW_TAG_formal_parameter;
|
||||||
|
|
||||||
TRACE("%s, for %s\n", dwarf2_debug_ctx(subpgm->ctx), dwarf2_debug_di(di));
|
TRACE("%s, for %s\n", dwarf2_debug_ctx(subpgm->ctx), dwarf2_debug_di(di));
|
||||||
|
|
||||||
param_type = dwarf2_lookup_type(subpgm->ctx, di);
|
param_type = dwarf2_lookup_type(subpgm->ctx, di);
|
||||||
dwarf2_find_name(subpgm->ctx, di, &name, "parameter");
|
dwarf2_find_name(subpgm->ctx, di, &name, "parameter");
|
||||||
if (dwarf2_compute_location(subpgm->ctx, di, DW_AT_location, &offset, &in_reg))
|
if (dwarf2_compute_location_attr(subpgm->ctx, di, DW_AT_location,
|
||||||
|
&loc, &subpgm->frame))
|
||||||
{
|
{
|
||||||
struct attribute ext;
|
struct attribute ext;
|
||||||
|
|
||||||
TRACE("found parameter %s/%ld (reg=%d) at %s\n",
|
if (loc.kind >= loc_user)
|
||||||
name.u.string, offset, in_reg, dwarf2_debug_ctx(subpgm->ctx));
|
|
||||||
switch (in_reg & ~Wine_DW_register_deref)
|
|
||||||
{
|
{
|
||||||
case Wine_DW_no_register:
|
FIXME("Unsupported yet location list in %s on variable %s\n",
|
||||||
|
subpgm->func->hash_elt.name, name.u.string);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subpgm->frame.kind >= loc_user)
|
||||||
|
{
|
||||||
|
FIXME("Unsupported yet location list in %s on frame for var %s\n",
|
||||||
|
subpgm->func->hash_elt.name, name.u.string);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("found parameter %s/%ld (reg=%d) at %s\n",
|
||||||
|
name.u.string, loc.offset, loc.reg,
|
||||||
|
dwarf2_debug_ctx(subpgm->ctx));
|
||||||
|
switch (loc.kind)
|
||||||
|
{
|
||||||
|
case loc_absolute:
|
||||||
/* it's a global variable */
|
/* it's a global variable */
|
||||||
/* FIXME: we don't handle it's scope yet */
|
/* FIXME: we don't handle it's scope yet */
|
||||||
if (!dwarf2_find_attribute(subpgm->ctx, di, DW_AT_external, &ext))
|
if (!dwarf2_find_attribute(subpgm->ctx, di, DW_AT_external, &ext))
|
||||||
ext.u.uvalue = 0;
|
ext.u.uvalue = 0;
|
||||||
symt_new_global_variable(subpgm->ctx->module, subpgm->compiland,
|
symt_new_global_variable(subpgm->ctx->module, subpgm->compiland,
|
||||||
name.u.string, !ext.u.uvalue,
|
name.u.string, !ext.u.uvalue,
|
||||||
subpgm->ctx->module->module.BaseOfImage + offset,
|
subpgm->ctx->module->module.BaseOfImage + loc.offset,
|
||||||
0, param_type);
|
0, param_type);
|
||||||
break;
|
break;
|
||||||
case Wine_DW_frame_register:
|
case loc_register:
|
||||||
in_reg = subpgm->frame_reg | Wine_DW_register_deref;
|
case loc_regrel:
|
||||||
offset += subpgm->frame_offset;
|
|
||||||
/* fall through */
|
|
||||||
default:
|
|
||||||
/* either a pmt/variable relative to frame pointer or
|
/* either a pmt/variable relative to frame pointer or
|
||||||
* pmt/variable in a register
|
* pmt/variable in a register
|
||||||
*/
|
*/
|
||||||
assert(subpgm->func);
|
assert(subpgm->func);
|
||||||
symt_add_func_local(subpgm->ctx->module, subpgm->func,
|
symt_add_func_local(subpgm->ctx->module, subpgm->func,
|
||||||
is_pmt ? DataIsParam : DataIsLocal,
|
is_pmt ? DataIsParam : DataIsLocal,
|
||||||
dwarf2_map_register(in_reg & ~Wine_DW_register_deref),
|
loc.reg, loc.kind == loc_regrel,
|
||||||
in_reg & Wine_DW_register_deref,
|
loc.offset, block, param_type, name.u.string);
|
||||||
offset, block, param_type, name.u.string);
|
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
FIXME("Unsupported\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dwarf2_find_attribute(subpgm->ctx, di, DW_AT_const_value, &value))
|
if (dwarf2_find_attribute(subpgm->ctx, di, DW_AT_const_value, &value))
|
||||||
|
@ -1399,20 +1452,13 @@ static struct symt* dwarf2_parse_subprogram(dwarf2_parse_context_t* ctx,
|
||||||
|
|
||||||
subpgm.ctx = ctx;
|
subpgm.ctx = ctx;
|
||||||
subpgm.compiland = compiland;
|
subpgm.compiland = compiland;
|
||||||
if (dwarf2_compute_location(ctx, di, DW_AT_frame_base, &subpgm.frame_offset, &subpgm.frame_reg)) {
|
if (!dwarf2_compute_location_attr(ctx, di, DW_AT_frame_base,
|
||||||
TRACE("For %s got %ld/%d\n", name.u.string, subpgm.frame_offset, subpgm.frame_reg);
|
&subpgm.frame, NULL))
|
||||||
if (subpgm.frame_reg == Wine_DW_no_register) {
|
|
||||||
/* Likely a constant, meaning a location list offset.
|
|
||||||
We do not handle those yet. */
|
|
||||||
/*FIXME("need to handle location lists\n"); */
|
|
||||||
subpgm.frame_reg = 0;
|
|
||||||
subpgm.frame_offset = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* on stack !! */
|
|
||||||
{
|
{
|
||||||
subpgm.frame_reg = 0;
|
/* on stack !! */
|
||||||
subpgm.frame_offset = 0;
|
subpgm.frame.kind = loc_regrel;
|
||||||
|
subpgm.frame.reg = 0;
|
||||||
|
subpgm.frame.offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (di->abbrev->have_child) /** any interest to not have child ? */
|
if (di->abbrev->have_child) /** any interest to not have child ? */
|
||||||
|
@ -1558,8 +1604,9 @@ static void dwarf2_load_one_entry(dwarf2_parse_context_t* ctx,
|
||||||
subpgm.ctx = ctx;
|
subpgm.ctx = ctx;
|
||||||
subpgm.compiland = compiland;
|
subpgm.compiland = compiland;
|
||||||
subpgm.func = NULL;
|
subpgm.func = NULL;
|
||||||
subpgm.frame_offset = 0;
|
subpgm.frame.kind = loc_absolute;
|
||||||
subpgm.frame_reg = 0;
|
subpgm.frame.offset = 0;
|
||||||
|
subpgm.frame.reg = Wine_DW_no_register;
|
||||||
dwarf2_parse_variable(&subpgm, NULL, di);
|
dwarf2_parse_variable(&subpgm, NULL, di);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1856,7 +1903,7 @@ BOOL dwarf2_parse(struct module* module, unsigned long load_offset,
|
||||||
const unsigned char* loclist, unsigned int loclist_size)
|
const unsigned char* loclist, unsigned int loclist_size)
|
||||||
{
|
{
|
||||||
dwarf2_section_t section[section_max];
|
dwarf2_section_t section[section_max];
|
||||||
char* ptr;
|
unsigned char* ptr;
|
||||||
const unsigned char*comp_unit_cursor = debug;
|
const unsigned char*comp_unit_cursor = debug;
|
||||||
const unsigned char*end_debug = debug + debug_size;
|
const unsigned char*end_debug = debug + debug_size;
|
||||||
|
|
||||||
|
@ -1877,7 +1924,7 @@ BOOL dwarf2_parse(struct module* module, unsigned long load_offset,
|
||||||
*/
|
*/
|
||||||
module->dwarf2_info = HeapAlloc(GetProcessHeap(), 0, sizeof(*module->dwarf2_info) + loclist_size);
|
module->dwarf2_info = HeapAlloc(GetProcessHeap(), 0, sizeof(*module->dwarf2_info) + loclist_size);
|
||||||
if (!module->dwarf2_info) return FALSE;
|
if (!module->dwarf2_info) return FALSE;
|
||||||
ptr = (char*)(module->dwarf2_info + 1);
|
ptr = (unsigned char*)(module->dwarf2_info + 1);
|
||||||
memcpy(ptr, loclist, loclist_size);
|
memcpy(ptr, loclist, loclist_size);
|
||||||
module->dwarf2_info->debug_loc.address = ptr;
|
module->dwarf2_info->debug_loc.address = ptr;
|
||||||
module->dwarf2_info->debug_loc.size = loclist_size;
|
module->dwarf2_info->debug_loc.size = loclist_size;
|
||||||
|
|
Loading…
Reference in New Issue