- fixed regression in ctrl-c handling
- fixed regression in 'info symbol XXXX' command (and enhanced presentation) - fixed regression in line stepping - fixed regression in & (address operator) handling - fixed some bad module reference for local symbols - enhanced register presentation as local variables - added warning when launching a debuggee which isn't a Wine app - removed the 'local' extension of display command (and check when setting the display whether the expr has a local binding) - simplified exception handling, and factorized some code when debugger stops
This commit is contained in:
parent
75e02e9335
commit
5fe480b472
@ -1676,6 +1676,13 @@ set $BreakAllThreadsStartup = 1
|
||||
after the execution of any <command>winedbg</command>
|
||||
command.
|
||||
</para>
|
||||
<para>
|
||||
<command>winedbg</command> will automatically detect if the
|
||||
expression you entered contains a local variable. If so,
|
||||
display will only be shown if the context is still in the
|
||||
same function as the one the debugger was in when the
|
||||
display expression was entered.
|
||||
</para>
|
||||
<para>
|
||||
<table>
|
||||
<title>WineDbg's displays</title>
|
||||
|
@ -26,20 +26,6 @@
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
|
||||
|
||||
/***********************************************************************
|
||||
* is_at_func_return
|
||||
*
|
||||
* Determine if the instruction at current PC is an instruction that
|
||||
* is a function return.
|
||||
*/
|
||||
static BOOL is_at_func_return(void)
|
||||
{
|
||||
ADDRESS addr;
|
||||
|
||||
memory_get_current_pc(&addr);
|
||||
return be_cpu->is_function_return(memory_to_linear_addr(&addr));
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* break_set_xpoints
|
||||
*
|
||||
@ -703,13 +689,14 @@ static BOOL should_stop(int bpnum)
|
||||
* Determine if we should continue execution after a SIGTRAP signal when
|
||||
* executing in the given mode.
|
||||
*/
|
||||
BOOL break_should_continue(ADDRESS* addr, DWORD code, int* count)
|
||||
BOOL break_should_continue(ADDRESS* addr, DWORD code, int* count, BOOL* is_break)
|
||||
{
|
||||
int bpnum;
|
||||
DWORD oldval;
|
||||
int wpnum;
|
||||
enum dbg_exec_mode mode = dbg_curr_thread->exec_mode;
|
||||
|
||||
*is_break = FALSE;
|
||||
/* If not single-stepping, back up to the break instruction */
|
||||
if (code == EXCEPTION_BREAKPOINT)
|
||||
addr->Offset += be_cpu->adjust_pc_for_break(&dbg_context, TRUE);
|
||||
@ -724,7 +711,6 @@ BOOL break_should_continue(ADDRESS* addr, DWORD code, int* count)
|
||||
dbg_printf("Stopped on breakpoint %d at ", bpnum);
|
||||
print_address(&dbg_curr_process->bp[bpnum].addr, TRUE);
|
||||
dbg_printf("\n");
|
||||
source_list_from_addr(addr, 0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -741,7 +727,6 @@ BOOL break_should_continue(ADDRESS* addr, DWORD code, int* count)
|
||||
print_address(addr, TRUE);
|
||||
dbg_printf(" values: old=%lu new=%lu\n",
|
||||
oldval, dbg_curr_process->bp[wpnum].w.oldval);
|
||||
source_list_from_addr(addr, 0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -770,19 +755,13 @@ BOOL break_should_continue(ADDRESS* addr, DWORD code, int* count)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are about to stop, then print out the source line if we
|
||||
* have it.
|
||||
*/
|
||||
if (mode != dbg_exec_cont && mode != dbg_exec_finish)
|
||||
source_list_from_addr(addr, 0);
|
||||
|
||||
/* If there's no breakpoint and we are not single-stepping, then
|
||||
* either we must have encountered a break insn in the Windows program
|
||||
* or someone is trying to stop us
|
||||
*/
|
||||
if (bpnum == -1 && code == EXCEPTION_BREAKPOINT)
|
||||
{
|
||||
*is_break = TRUE;
|
||||
addr->Offset += be_cpu->adjust_pc_for_break(&dbg_context, FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
@ -815,8 +794,10 @@ void break_restart_execution(int count)
|
||||
enum dbg_line_status status;
|
||||
enum dbg_exec_mode mode, ret_mode;
|
||||
ADDRESS callee;
|
||||
void* linear;
|
||||
|
||||
memory_get_current_pc(&addr);
|
||||
linear = memory_to_linear_addr(&addr);
|
||||
|
||||
/*
|
||||
* This is the mode we will be running in after we finish. We would like
|
||||
@ -841,7 +822,7 @@ void break_restart_execution(int count)
|
||||
dbg_printf("Not stopped at any breakpoint; argument ignored.\n");
|
||||
}
|
||||
|
||||
if (mode == dbg_exec_finish && is_at_func_return())
|
||||
if (mode == dbg_exec_finish && be_cpu->is_function_return(linear))
|
||||
{
|
||||
mode = ret_mode = dbg_exec_step_into_insn;
|
||||
}
|
||||
@ -852,7 +833,7 @@ void break_restart_execution(int count)
|
||||
* FIXME - we need to check for things like thunks or trampolines,
|
||||
* as the actual function may in fact have debug info.
|
||||
*/
|
||||
if (be_cpu->is_function_call(memory_to_linear_addr(&addr), &callee))
|
||||
if (be_cpu->is_function_call(linear, &callee))
|
||||
{
|
||||
status = symbol_get_function_line_status(&callee);
|
||||
#if 0
|
||||
@ -909,6 +890,8 @@ void break_restart_execution(int count)
|
||||
dbg_curr_process->bp[0].enabled = TRUE;
|
||||
dbg_curr_process->bp[0].refcount = 1;
|
||||
dbg_curr_process->bp[0].skipcount = 0;
|
||||
dbg_curr_process->bp[0].xpoint_type = be_xpoint_break;
|
||||
dbg_curr_process->bp[0].condition = NULL;
|
||||
be_cpu->single_step(&dbg_context, FALSE);
|
||||
break_set_xpoints(TRUE);
|
||||
break;
|
||||
@ -917,14 +900,15 @@ void break_restart_execution(int count)
|
||||
case dbg_exec_finish:
|
||||
case dbg_exec_step_over_insn: /* Stepping over a call */
|
||||
case dbg_exec_step_over_line: /* Stepping over a call */
|
||||
if (be_cpu->is_step_over_insn(memory_to_linear_addr(&addr)))
|
||||
if (be_cpu->is_step_over_insn(linear))
|
||||
{
|
||||
be_cpu->single_step(&dbg_context, FALSE);
|
||||
be_cpu->disasm_one_insn(&addr, FALSE);
|
||||
dbg_curr_process->bp[0].addr = addr;
|
||||
dbg_curr_process->bp[0].enabled = TRUE;
|
||||
dbg_curr_process->bp[0].refcount = 1;
|
||||
dbg_curr_process->bp[0].skipcount = 0;
|
||||
dbg_curr_process->bp[0].xpoint_type = be_xpoint_break;
|
||||
dbg_curr_process->bp[0].condition = NULL;
|
||||
be_cpu->single_step(&dbg_context, FALSE);
|
||||
break_set_xpoints(TRUE);
|
||||
break;
|
||||
@ -956,7 +940,7 @@ int break_add_condition(int num, struct expr* exp)
|
||||
dbg_curr_process->bp[num].condition = NULL;
|
||||
}
|
||||
|
||||
if (exp != NULL) dbg_curr_process->bp[num].condition = expr_clone(exp);
|
||||
if (exp != NULL) dbg_curr_process->bp[num].condition = expr_clone(exp, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -232,10 +232,8 @@ watch_command:
|
||||
|
||||
display_command:
|
||||
tDISPLAY { display_print(); }
|
||||
| tDISPLAY expr { display_add($2, 1, 0, FALSE); }
|
||||
| tDISPLAY tFORMAT expr { display_add($3, $2 >> 8, $2 & 0xff, FALSE); }
|
||||
| tLOCAL tDISPLAY expr { display_add($3, 1, 0, TRUE); }
|
||||
| tLOCAL tDISPLAY tFORMAT expr { display_add($4, $3 >> 8, $3 & 0xff, TRUE); }
|
||||
| tDISPLAY expr { display_add($2, 1, 0); }
|
||||
| tDISPLAY tFORMAT expr { display_add($3, $2 >> 8, $2 & 0xff); }
|
||||
| tENABLE tDISPLAY tNUM { display_enable($3, TRUE); }
|
||||
| tDISABLE tDISPLAY tNUM { display_enable($3, FALSE); }
|
||||
| tDELETE tDISPLAY tNUM { display_delete($3); }
|
||||
@ -413,7 +411,6 @@ static WINE_EXCEPTION_FILTER(wine_dbg_cmd)
|
||||
break;
|
||||
case CONTROL_C_EXIT:
|
||||
/* this is generally sent by a ctrl-c when we run winedbg outside of wineconsole */
|
||||
dbg_printf("\nCtrl-C\n");
|
||||
/* stop the debuggee, and continue debugger execution, we will be reentered by the
|
||||
* debug events generated by stopping
|
||||
*/
|
||||
|
@ -161,7 +161,6 @@ struct dbg_thread
|
||||
HANDLE handle;
|
||||
DWORD tid;
|
||||
void* teb;
|
||||
int wait_for_first_exception;
|
||||
enum dbg_exec_mode exec_mode; /* mode the thread is run (step/run...) */
|
||||
int exec_count; /* count of mode operations */
|
||||
ADDRESS_MODE addr_mode; /* mode */
|
||||
@ -252,7 +251,7 @@ extern void break_delete_xpoint(int num);
|
||||
extern void break_delete_xpoints_from_module(unsigned long base);
|
||||
extern void break_enable_xpoint(int num, BOOL enable);
|
||||
extern void break_info(void);
|
||||
extern BOOL break_should_continue(ADDRESS* addr, DWORD code, int* count);
|
||||
extern BOOL break_should_continue(ADDRESS* addr, DWORD code, int* count, BOOL* is_break);
|
||||
extern void break_suspend_execution(void);
|
||||
extern void break_restart_execution(int count);
|
||||
extern int break_add_condition(int bpnum, struct expr* exp);
|
||||
@ -268,7 +267,7 @@ extern char* lexeme_alloc(const char*);
|
||||
|
||||
/* display.c */
|
||||
extern int display_print(void);
|
||||
extern int display_add(struct expr* exp, int count, char format, int local_frame);
|
||||
extern int display_add(struct expr* exp, int count, char format);
|
||||
extern int display_delete(int displaynum);
|
||||
extern int display_info(void);
|
||||
extern int display_enable(int displaynum, int enable);
|
||||
@ -287,7 +286,7 @@ extern struct expr* expr_alloc_struct(struct expr*, const char* element);
|
||||
extern struct expr* expr_alloc_func_call(const char*, int nargs, ...);
|
||||
extern struct expr* expr_alloc_typecast(struct type_expr_t*, struct expr*);
|
||||
extern struct dbg_lvalue expr_eval(struct expr*);
|
||||
extern struct expr* expr_clone(const struct expr* exp);
|
||||
extern struct expr* expr_clone(const struct expr* exp, unsigned* local_binding);
|
||||
extern int expr_free(struct expr* exp);
|
||||
extern int expr_print(const struct expr* exp);
|
||||
|
||||
@ -342,6 +341,7 @@ extern enum dbg_line_status symbol_get_function_line_status(const ADDRESS* addr)
|
||||
extern BOOL symbol_get_line(const char* filename, const char* func, IMAGEHLP_LINE* ret);
|
||||
extern void symbol_info(const char* str);
|
||||
extern int symbol_info_locals(void);
|
||||
extern BOOL symbol_is_local(const char* name);
|
||||
|
||||
/* types.c */
|
||||
extern void print_value(const struct dbg_lvalue* addr, char format, int level);
|
||||
|
@ -57,9 +57,10 @@ static inline BOOL cmp_symbol(const SYMBOL_INFO* si1, const SYMBOL_INFO* si2)
|
||||
!memcmp(si1->Name, si2->Name, si1->NameLen);
|
||||
}
|
||||
|
||||
int display_add(struct expr *exp, int count, char format, int in_frame)
|
||||
int display_add(struct expr *exp, int count, char format)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
int local_binding = FALSE;
|
||||
|
||||
for (i = 0; i < ndisplays; i++)
|
||||
if (displaypoints[i].exp == NULL)
|
||||
@ -75,11 +76,11 @@ int display_add(struct expr *exp, int count, char format, int in_frame)
|
||||
|
||||
if (i == ndisplays) ndisplays++;
|
||||
|
||||
displaypoints[i].exp = expr_clone(exp);
|
||||
displaypoints[i].exp = expr_clone(exp, &local_binding);
|
||||
displaypoints[i].count = count;
|
||||
displaypoints[i].format = format;
|
||||
displaypoints[i].enabled = TRUE;
|
||||
if (in_frame)
|
||||
if (local_binding)
|
||||
{
|
||||
displaypoints[i].func = (SYMBOL_INFO*)displaypoints[i].func_buffer;
|
||||
memset(displaypoints[i].func, 0, sizeof(SYMBOL_INFO));
|
||||
|
@ -313,8 +313,8 @@ struct dbg_lvalue expr_eval(struct expr* exp)
|
||||
case type_expr_udt_class:
|
||||
case type_expr_udt_struct:
|
||||
case type_expr_udt_union:
|
||||
rtn.type = types_find_type((DWORD)memory_to_linear_addr(&rtn.addr),
|
||||
exp->un.cast.cast_to.u.name, SymTagUDT);
|
||||
rtn.type = types_find_type(rtn.type.module, exp->un.cast.cast_to.u.name,
|
||||
SymTagUDT);
|
||||
if (rtn.type.id == dbg_itype_none)
|
||||
{
|
||||
dbg_printf("Can't cast to UDT %s\n", exp->un.cast.cast_to.u.name);
|
||||
@ -322,8 +322,8 @@ struct dbg_lvalue expr_eval(struct expr* exp)
|
||||
}
|
||||
break;
|
||||
case type_expr_enumeration:
|
||||
rtn.type = types_find_type((DWORD)memory_to_linear_addr(&rtn.addr),
|
||||
exp->un.cast.cast_to.u.name, SymTagEnum);
|
||||
rtn.type = types_find_type(rtn.type.module, exp->un.cast.cast_to.u.name,
|
||||
SymTagEnum);
|
||||
if (rtn.type.id == dbg_itype_none)
|
||||
{
|
||||
dbg_printf("Can't cast to enumeration %s\n", exp->un.cast.cast_to.u.name);
|
||||
@ -643,6 +643,8 @@ struct dbg_lvalue expr_eval(struct expr* exp)
|
||||
RaiseException(DEBUG_STATUS_CANT_DEREF, 0, 0, NULL);
|
||||
exp->un.unop.result = (unsigned int)memory_to_linear_addr(&exp1.addr);
|
||||
rtn.type = types_find_pointer(&exp1.type);
|
||||
if (rtn.type.id == dbg_itype_none)
|
||||
RaiseException(DEBUG_STATUS_CANT_DEREF, 0, 0, NULL);
|
||||
break;
|
||||
default: RaiseException(DEBUG_STATUS_INTERNAL_ERROR, 0, 0, NULL);
|
||||
}
|
||||
@ -770,7 +772,7 @@ int expr_print(const struct expr* exp)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct expr* expr_clone(const struct expr* exp)
|
||||
struct expr* expr_clone(const struct expr* exp, unsigned* local_binding)
|
||||
{
|
||||
int i;
|
||||
struct expr* rtn;
|
||||
@ -785,7 +787,7 @@ struct expr* expr_clone(const struct expr* exp)
|
||||
switch (exp->type)
|
||||
{
|
||||
case EXPR_TYPE_CAST:
|
||||
rtn->un.cast.expr = expr_clone(exp->un.cast.expr);
|
||||
rtn->un.cast.expr = expr_clone(exp->un.cast.expr, local_binding);
|
||||
break;
|
||||
case EXPR_TYPE_INTVAR:
|
||||
rtn->un.intvar.name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(exp->un.intvar.name) + 1), exp->un.intvar.name);
|
||||
@ -798,25 +800,27 @@ struct expr* expr_clone(const struct expr* exp)
|
||||
break;
|
||||
case EXPR_TYPE_SYMBOL:
|
||||
rtn->un.symbol.name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(exp->un.symbol.name) + 1), exp->un.symbol.name);
|
||||
if (local_binding && symbol_is_local(exp->un.symbol.name))
|
||||
*local_binding = TRUE;
|
||||
break;
|
||||
case EXPR_TYPE_PSTRUCT:
|
||||
case EXPR_TYPE_STRUCT:
|
||||
rtn->un.structure.exp1 = expr_clone(exp->un.structure.exp1);
|
||||
rtn->un.structure.exp1 = expr_clone(exp->un.structure.exp1, local_binding);
|
||||
rtn->un.structure.element_name = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(exp->un.structure.element_name) + 1), exp->un.structure.element_name);
|
||||
break;
|
||||
case EXPR_TYPE_CALL:
|
||||
for (i = 0; i < exp->un.call.nargs; i++)
|
||||
{
|
||||
rtn->un.call.arg[i] = expr_clone(exp->un.call.arg[i]);
|
||||
rtn->un.call.arg[i] = expr_clone(exp->un.call.arg[i], local_binding);
|
||||
}
|
||||
rtn->un.call.funcname = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(exp->un.call.funcname) + 1), exp->un.call.funcname);
|
||||
break;
|
||||
case EXPR_TYPE_BINOP:
|
||||
rtn->un.binop.exp1 = expr_clone(exp->un.binop.exp1);
|
||||
rtn->un.binop.exp2 = expr_clone(exp->un.binop.exp2);
|
||||
rtn->un.binop.exp1 = expr_clone(exp->un.binop.exp1, local_binding);
|
||||
rtn->un.binop.exp2 = expr_clone(exp->un.binop.exp2, local_binding);
|
||||
break;
|
||||
case EXPR_TYPE_UNOP:
|
||||
rtn->un.unop.exp1 = expr_clone(exp->un.unop.exp1);
|
||||
rtn->un.unop.exp1 = expr_clone(exp->un.unop.exp1, local_binding);
|
||||
break;
|
||||
default:
|
||||
WINE_FIXME("Unexpected expression (%u).\n", exp->type);
|
||||
|
@ -263,7 +263,6 @@ static void print_typed_basic(const struct dbg_lvalue* lvalue)
|
||||
long double val_real;
|
||||
DWORD tag, size, count, bt;
|
||||
struct dbg_type rtype;
|
||||
DWORD linear = (DWORD)memory_to_linear_addr(&lvalue->addr);
|
||||
|
||||
if (lvalue->type.id == dbg_itype_none ||
|
||||
!types_get_info(&lvalue->type, TI_GET_SYMTAG, &tag))
|
||||
@ -362,7 +361,7 @@ static void print_typed_basic(const struct dbg_lvalue* lvalue)
|
||||
fcp->Count = min(count, 256);
|
||||
if (types_get_info(&lvalue->type, TI_FINDCHILDREN, fcp))
|
||||
{
|
||||
type.module = linear;
|
||||
type.module = lvalue->type.module;
|
||||
for (i = 0; i < min(fcp->Count, count); i++)
|
||||
{
|
||||
type.id = fcp->ChildId[i];
|
||||
@ -484,13 +483,15 @@ void print_address(const ADDRESS* addr, BOOLEAN with_line)
|
||||
char buffer[sizeof(SYMBOL_INFO) + 256];
|
||||
SYMBOL_INFO* si = (SYMBOL_INFO*)buffer;
|
||||
void* lin = memory_to_linear_addr(addr);
|
||||
DWORD disp;
|
||||
|
||||
print_bare_address(addr);
|
||||
|
||||
si->SizeOfStruct = sizeof(*si);
|
||||
si->MaxNameLen = 256;
|
||||
if (!SymFromAddr(dbg_curr_process->handle, (unsigned long)lin, NULL, si)) return;
|
||||
if (!SymFromAddr(dbg_curr_process->handle, (unsigned long)lin, &disp, si)) return;
|
||||
dbg_printf(" %s", si->Name);
|
||||
if (disp) dbg_printf("+0x%lx", disp);
|
||||
if (with_line)
|
||||
{
|
||||
IMAGEHLP_LINE il;
|
||||
|
@ -358,17 +358,17 @@ void source_list(IMAGEHLP_LINE* src1, IMAGEHLP_LINE* src2, int delta)
|
||||
void source_list_from_addr(const ADDRESS* addr, int nlines)
|
||||
{
|
||||
IMAGEHLP_LINE il;
|
||||
DWORD lin;
|
||||
ADDRESS la;
|
||||
|
||||
if (!addr)
|
||||
{
|
||||
ADDRESS la;
|
||||
memory_get_current_pc(&la);
|
||||
lin = (unsigned long)memory_to_linear_addr(&la);
|
||||
addr = &la;
|
||||
}
|
||||
else lin = (unsigned long)memory_to_linear_addr(addr);
|
||||
|
||||
il.SizeOfStruct = sizeof(il);
|
||||
if (SymGetLineFromAddr(dbg_curr_process->handle, lin, NULL, &il))
|
||||
if (SymGetLineFromAddr(dbg_curr_process->handle,
|
||||
(unsigned long)memory_to_linear_addr(addr),
|
||||
NULL, &il))
|
||||
source_list(&il, NULL, nlines);
|
||||
}
|
||||
|
@ -287,11 +287,15 @@ enum sym_get_lval symbol_get_lvalue(const char* name, const int lineno,
|
||||
dbg_printf("[%d]: ", i + 1);
|
||||
if (sgv.syms[i].flags & SYMFLAG_LOCAL)
|
||||
{
|
||||
dbg_printf("local variable of %s\n", si->Name);
|
||||
dbg_printf("local variable %sof %s\n",
|
||||
sgv.syms[i].flags & SYMFLAG_REGISTER ? "(in a register) " : "",
|
||||
si->Name);
|
||||
}
|
||||
else if (sgv.syms[i].flags & SYMFLAG_PARAMETER)
|
||||
{
|
||||
dbg_printf("parameter of %s\n", si->Name);
|
||||
dbg_printf("parameter %sof %s\n",
|
||||
sgv.syms[i].flags & SYMFLAG_REGISTER ? "(in a register) " : "",
|
||||
si->Name);
|
||||
}
|
||||
else if (sgv.syms[i].flags & SYMFLAG_THUNK)
|
||||
{
|
||||
@ -333,6 +337,28 @@ enum sym_get_lval symbol_get_lvalue(const char* name, const int lineno,
|
||||
return sglv_found;
|
||||
}
|
||||
|
||||
BOOL symbol_is_local(const char* name)
|
||||
{
|
||||
struct sgv_data sgv;
|
||||
char tmp[sizeof(SYMBOL_INFO) + 256];
|
||||
SYMBOL_INFO* si = (SYMBOL_INFO*)tmp;
|
||||
|
||||
sgv.num = 0;
|
||||
sgv.num_thunks = 0;
|
||||
sgv.name = name;
|
||||
sgv.filename = NULL;
|
||||
sgv.lineno = 0;
|
||||
sgv.bp_disp = FALSE;
|
||||
sgv.do_thunks = FALSE;
|
||||
|
||||
si->SizeOfStruct = sizeof(*si);
|
||||
si->MaxNameLen = 256;
|
||||
if (stack_get_frame(si, &sgv.ihsf) &&
|
||||
SymSetContext(dbg_curr_process->handle, &sgv.ihsf, NULL))
|
||||
SymEnumSymbols(dbg_curr_process->handle, 0, name, sgv_cb, (void*)&sgv);
|
||||
return sgv.num > 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* symbol_read_symtable
|
||||
*
|
||||
@ -343,8 +369,8 @@ void symbol_read_symtable(const char* filename, unsigned long offset)
|
||||
dbg_printf("No longer supported\n");
|
||||
|
||||
#if 0
|
||||
/* FIXME: have to implement SymAddSymbol in dbghelp, but likely to link this with
|
||||
* a loaded module !!
|
||||
/* FIXME: have to implement SymAddSymbol in dbghelp, but likely we'll need to link
|
||||
* this with an already loaded module !!
|
||||
*/
|
||||
FILE* symbolfile;
|
||||
unsigned addr;
|
||||
@ -575,14 +601,30 @@ int symbol_info_locals(void)
|
||||
static BOOL CALLBACK symbols_info_cb(SYMBOL_INFO* sym, ULONG size, void* ctx)
|
||||
{
|
||||
struct dbg_type type;
|
||||
IMAGEHLP_MODULE mi;
|
||||
|
||||
mi.SizeOfStruct = sizeof(mi);
|
||||
|
||||
if (!SymGetModuleInfo(dbg_curr_process->handle, sym->ModBase, &mi))
|
||||
mi.ModuleName[0] = '\0';
|
||||
else
|
||||
{
|
||||
size_t len = strlen(mi.ModuleName);
|
||||
if (len > 5 && !strcmp(mi.ModuleName + len - 5, "<elf>"))
|
||||
mi.ModuleName[len - 5] = '\0';
|
||||
}
|
||||
|
||||
dbg_printf("%08lx: %s!%s", sym->Address, mi.ModuleName, sym->Name);
|
||||
type.id = sym->TypeIndex;
|
||||
type.module = sym->ModBase;
|
||||
|
||||
dbg_printf("%08lx: %s (", sym->Address, sym->Name);
|
||||
if (sym->TypeIndex != dbg_itype_none && sym->TypeIndex != 0 &&
|
||||
types_get_info(&type, TI_GET_TYPE, &type.id))
|
||||
{
|
||||
dbg_printf(" ");
|
||||
types_print_type(&type, FALSE);
|
||||
}
|
||||
dbg_printf(")\n");
|
||||
dbg_printf("\n");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -274,12 +274,12 @@ BOOL types_array_index(const struct dbg_lvalue* lvalue, int index,
|
||||
|
||||
struct type_find_t
|
||||
{
|
||||
unsigned long result; /* out: the found type */
|
||||
unsigned long result; /* out: the found type */
|
||||
enum SymTagEnum tag; /* in: the tag to look for */
|
||||
union
|
||||
{
|
||||
unsigned long typeid;
|
||||
const char* name;
|
||||
unsigned long typeid; /* when tag is SymTagUDT */
|
||||
const char* name; /* when tag is SymTagPointerType */
|
||||
} u;
|
||||
};
|
||||
|
||||
@ -288,6 +288,7 @@ static BOOL CALLBACK types_cb(PSYMBOL_INFO sym, ULONG size, void* _user)
|
||||
struct type_find_t* user = (struct type_find_t*)_user;
|
||||
BOOL ret = TRUE;
|
||||
struct dbg_type type;
|
||||
DWORD type_id;
|
||||
|
||||
if (sym->Tag == user->tag)
|
||||
{
|
||||
@ -303,11 +304,13 @@ static BOOL CALLBACK types_cb(PSYMBOL_INFO sym, ULONG size, void* _user)
|
||||
case SymTagPointerType:
|
||||
type.module = sym->ModBase;
|
||||
type.id = sym->TypeIndex;
|
||||
if (types_get_info(&type, TI_GET_TYPE, &type.id) && type.id == user->u.typeid)
|
||||
types_get_info(&type, TI_GET_TYPE, &type_id);
|
||||
if (types_get_info(&type, TI_GET_TYPE, &type_id) && type_id == user->u.typeid)
|
||||
{
|
||||
user->result = sym->TypeIndex;
|
||||
ret = FALSE;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@ -413,7 +416,7 @@ void print_value(const struct dbg_lvalue* lvalue, char format, int level)
|
||||
for (i = 0; i < min(fcp->Count, count); i++)
|
||||
{
|
||||
ptr = NULL;
|
||||
type.module = (unsigned long)memory_to_linear_addr(&lvalue->addr);
|
||||
type.module = lvalue->type.module;
|
||||
type.id = fcp->ChildId[i];
|
||||
types_get_info(&type, TI_GET_SYMNAME, &ptr);
|
||||
if (!ptr) continue;
|
||||
@ -546,6 +549,7 @@ int types_print_type(const struct dbg_type* type, BOOL details)
|
||||
case UdtStruct: dbg_printf("struct %s", name); break;
|
||||
case UdtUnion: dbg_printf("union %s", name); break;
|
||||
case UdtClass: dbg_printf("class %s", name); break;
|
||||
default: WINE_ERR("Unsupported UDT type (%ld) for %s", udt, name); break;
|
||||
}
|
||||
if (details &&
|
||||
types_get_info(type, TI_GET_CHILDRENCOUNT, &count))
|
||||
|
@ -56,12 +56,7 @@
|
||||
* + all computations should be made on long long
|
||||
* o expr computations are in int:s
|
||||
* o bitfield size is on a 4-bytes
|
||||
* + some bits of internal types are missing (like type casts and the address
|
||||
* operator)
|
||||
* - execution:
|
||||
* + display: we shouldn't need to tell whether a display is local or not. This
|
||||
* should be automatically guessed by checking whether the variables that are
|
||||
* references are local or not
|
||||
* + set a better fix for gdb (proxy mode) than the step-mode hack
|
||||
* + implement function call in debuggee
|
||||
* + trampoline management is broken when getting 16 <=> 32 thunk destination
|
||||
@ -70,8 +65,10 @@
|
||||
* it currently stops at first insn with line number during the library
|
||||
* loading). We should identify this (__wine_delay_import) and set a
|
||||
* breakpoint instead of single stepping the library loading.
|
||||
* + Ctrl-C (in debugger) doesn't work if we've attached to the debuggee (but
|
||||
* works if winedbg started the debuggee)
|
||||
* + it's wrong to copy thread->step_over_bp into process->bp[0] (when
|
||||
* we have a multi-thread debuggee). complete fix must include storing all
|
||||
* thread's step-over bp in process-wide bp array, and not to handle bp
|
||||
* when we have the wrong thread running into that bp
|
||||
*/
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
|
||||
@ -331,7 +328,7 @@ struct dbg_thread* dbg_get_thread(struct dbg_process* p, DWORD tid)
|
||||
}
|
||||
|
||||
struct dbg_thread* dbg_add_thread(struct dbg_process* p, DWORD tid,
|
||||
HANDLE h, void* teb)
|
||||
HANDLE h, void* teb)
|
||||
{
|
||||
struct dbg_thread* t = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_thread));
|
||||
|
||||
@ -342,7 +339,6 @@ struct dbg_thread* dbg_add_thread(struct dbg_process* p, DWORD tid,
|
||||
t->tid = tid;
|
||||
t->teb = teb;
|
||||
t->process = p;
|
||||
t->wait_for_first_exception = 0;
|
||||
t->exec_mode = dbg_exec_cont;
|
||||
t->exec_count = 0;
|
||||
t->step_over_bp.enabled = FALSE;
|
||||
@ -375,10 +371,6 @@ static void dbg_init_current_thread(void* start)
|
||||
break_set_xpoints(TRUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_curr_thread->wait_for_first_exception = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void dbg_del_thread(struct dbg_thread* t)
|
||||
@ -463,9 +455,10 @@ static unsigned dbg_fetch_context(void)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static unsigned dbg_exception_prolog(BOOL is_debug, BOOL force, DWORD code)
|
||||
static unsigned dbg_exception_prolog(BOOL is_debug, DWORD code)
|
||||
{
|
||||
ADDRESS addr;
|
||||
BOOL is_break;
|
||||
|
||||
dbg_in_exception = TRUE;
|
||||
memory_get_current_pc(&addr);
|
||||
@ -491,9 +484,8 @@ static unsigned dbg_exception_prolog(BOOL is_debug, BOOL force, DWORD code)
|
||||
* is WRT the source files.
|
||||
*/
|
||||
stack_backtrace(dbg_curr_tid, FALSE);
|
||||
|
||||
if (!force && is_debug &&
|
||||
break_should_continue(&addr, code, &dbg_curr_thread->exec_count))
|
||||
if (is_debug &&
|
||||
break_should_continue(&addr, code, &dbg_curr_thread->exec_count, &is_break))
|
||||
return FALSE;
|
||||
|
||||
if (addr.Mode != dbg_curr_thread->addr_mode)
|
||||
@ -511,10 +503,9 @@ static unsigned dbg_exception_prolog(BOOL is_debug, BOOL force, DWORD code)
|
||||
dbg_printf("In %s mode.\n", name);
|
||||
dbg_curr_thread->addr_mode = addr.Mode;
|
||||
}
|
||||
|
||||
display_print();
|
||||
|
||||
if (!is_debug && !force)
|
||||
if (!is_debug)
|
||||
{
|
||||
/* This is a real crash, dump some info */
|
||||
be_cpu->print_context(dbg_curr_thread->handle, &dbg_context);
|
||||
@ -522,16 +513,17 @@ static unsigned dbg_exception_prolog(BOOL is_debug, BOOL force, DWORD code)
|
||||
be_cpu->print_segment_info(dbg_curr_thread->handle, &dbg_context);
|
||||
stack_backtrace(dbg_curr_tid, TRUE);
|
||||
}
|
||||
|
||||
if (!is_debug ||
|
||||
dbg_curr_thread->exec_mode == dbg_exec_step_over_insn ||
|
||||
dbg_curr_thread->exec_mode == dbg_exec_step_into_insn)
|
||||
if (!is_debug || is_break ||
|
||||
dbg_curr_thread->exec_mode == dbg_exec_step_over_insn ||
|
||||
dbg_curr_thread->exec_mode == dbg_exec_step_into_insn)
|
||||
{
|
||||
ADDRESS tmp = addr;
|
||||
/* Show where we crashed */
|
||||
dbg_curr_frame = 0;
|
||||
memory_disasm_one_insn(&addr);
|
||||
source_list_from_addr(&addr, 0);
|
||||
memory_disasm_one_insn(&tmp);
|
||||
}
|
||||
source_list_from_addr(&addr, 0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -548,8 +540,7 @@ static void dbg_exception_epilog(void)
|
||||
dbg_in_exception = FALSE;
|
||||
}
|
||||
|
||||
static DWORD dbg_handle_exception(EXCEPTION_RECORD* rec, BOOL first_chance,
|
||||
BOOL force)
|
||||
static DWORD dbg_handle_exception(EXCEPTION_RECORD* rec, BOOL first_chance)
|
||||
{
|
||||
BOOL is_debug = FALSE;
|
||||
THREADNAME_INFO* pThreadName;
|
||||
@ -557,6 +548,9 @@ static DWORD dbg_handle_exception(EXCEPTION_RECORD* rec, BOOL first_chance,
|
||||
|
||||
assert(dbg_curr_thread);
|
||||
|
||||
WINE_TRACE("exception=%lx first_chance=%c\n",
|
||||
rec->ExceptionCode, first_chance ? 'Y' : 'N');
|
||||
|
||||
switch (rec->ExceptionCode)
|
||||
{
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
@ -576,7 +570,7 @@ static DWORD dbg_handle_exception(EXCEPTION_RECORD* rec, BOOL first_chance,
|
||||
return DBG_CONTINUE;
|
||||
}
|
||||
|
||||
if (first_chance && !is_debug && !force && !DBG_IVAR(BreakOnFirstChance))
|
||||
if (first_chance && !is_debug && !DBG_IVAR(BreakOnFirstChance))
|
||||
{
|
||||
/* pass exception to program except for debug exceptions */
|
||||
return DBG_EXCEPTION_NOT_HANDLED;
|
||||
@ -693,12 +687,12 @@ static DWORD dbg_handle_exception(EXCEPTION_RECORD* rec, BOOL first_chance,
|
||||
|
||||
if (dbg_action_mode == automatic_mode)
|
||||
{
|
||||
dbg_exception_prolog(is_debug, FALSE, rec->ExceptionCode);
|
||||
dbg_exception_prolog(is_debug, rec->ExceptionCode);
|
||||
dbg_exception_epilog();
|
||||
return 0; /* terminate execution */
|
||||
}
|
||||
|
||||
if (dbg_exception_prolog(is_debug, force, rec->ExceptionCode))
|
||||
if (dbg_exception_prolog(is_debug, rec->ExceptionCode))
|
||||
{
|
||||
dbg_interactiveP = TRUE;
|
||||
return 0;
|
||||
@ -740,15 +734,12 @@ static unsigned dbg_handle_debug_event(DEBUG_EVENT* de)
|
||||
dbg_curr_process->continue_on_first_exception = FALSE;
|
||||
if (!DBG_IVAR(BreakOnAttach)) break;
|
||||
}
|
||||
|
||||
if (dbg_fetch_context())
|
||||
{
|
||||
cont = dbg_handle_exception(&de->u.Exception.ExceptionRecord,
|
||||
de->u.Exception.dwFirstChance,
|
||||
dbg_curr_thread->wait_for_first_exception);
|
||||
de->u.Exception.dwFirstChance);
|
||||
if (cont && dbg_curr_thread)
|
||||
{
|
||||
dbg_curr_thread->wait_for_first_exception = 0;
|
||||
SetThreadContext(dbg_curr_thread->handle, &dbg_context);
|
||||
}
|
||||
}
|
||||
@ -938,7 +929,6 @@ static void dbg_resume_debuggee(DWORD cont)
|
||||
{
|
||||
if (!SetThreadContext(dbg_curr_thread->handle, &dbg_context))
|
||||
dbg_printf("Cannot set ctx on %lu\n", dbg_curr_tid);
|
||||
dbg_curr_thread->wait_for_first_exception = 0;
|
||||
}
|
||||
}
|
||||
dbg_interactiveP = FALSE;
|
||||
@ -966,12 +956,12 @@ void dbg_wait_next_exception(DWORD cont, int count, int mode)
|
||||
dbg_interactiveP = TRUE;
|
||||
|
||||
memory_get_current_pc(&addr);
|
||||
WINE_TRACE("Exiting debugger PC=0x%lx mode=%d count=%d\n",
|
||||
WINE_TRACE("Entering debugger PC=0x%lx mode=%d count=%d\n",
|
||||
addr.Offset, dbg_curr_thread->exec_mode,
|
||||
dbg_curr_thread->exec_count);
|
||||
}
|
||||
|
||||
static DWORD dbg_main_loop(void)
|
||||
static unsigned dbg_main_loop(void)
|
||||
{
|
||||
DEBUG_EVENT de;
|
||||
|
||||
@ -994,7 +984,6 @@ static DWORD dbg_main_loop(void)
|
||||
break;
|
||||
default:
|
||||
dbg_interactiveP = TRUE;
|
||||
if (dbg_curr_process) source_list_from_addr(NULL, 0);
|
||||
parser(NULL);
|
||||
}
|
||||
dbg_printf("WineDbg terminated on pid 0x%lx\n", dbg_curr_pid);
|
||||
@ -1016,13 +1005,31 @@ static unsigned dbg_start_debuggee(LPSTR cmdLine)
|
||||
* while GUI:s don't
|
||||
*/
|
||||
if (!CreateProcess(NULL, cmdLine, NULL, NULL,
|
||||
FALSE,
|
||||
FALSE,
|
||||
DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS|CREATE_NEW_CONSOLE,
|
||||
NULL, NULL, &startup, &info))
|
||||
{
|
||||
dbg_printf("Couldn't start process '%s'\n", cmdLine);
|
||||
return FALSE;
|
||||
}
|
||||
if (!info.dwProcessId)
|
||||
{
|
||||
/* this happens when the program being run is not a Wine binary
|
||||
* (for example, a shell wrapper around a WineLib app)
|
||||
*/
|
||||
/* Current fix: list running processes and let the user attach
|
||||
* to one of them (sic)
|
||||
* FIXME: implement a real fix => grab the process (from the
|
||||
* running processes) from its name
|
||||
*/
|
||||
dbg_printf("Debuggee has been started (%s)\n"
|
||||
"But WineDbg isn't attached to it. Maybe you're trying to debug a winelib wrapper ??\n"
|
||||
"Try to attach to one of those processes:\n", cmdLine);
|
||||
/* FIXME: (HACK) we need some time before the wrapper executes the winelib app */
|
||||
Sleep(100);
|
||||
info_win32_processes();
|
||||
return TRUE;
|
||||
}
|
||||
dbg_curr_pid = info.dwProcessId;
|
||||
if (!(dbg_curr_process = dbg_add_process(dbg_curr_pid, 0, NULL))) return FALSE;
|
||||
|
||||
@ -1056,13 +1063,14 @@ void dbg_run_debuggee(const char* args)
|
||||
|
||||
BOOL dbg_interrupt_debuggee(void)
|
||||
{
|
||||
dbg_printf("Ctrl-C: stopping debuggee\n");
|
||||
if (!dbg_process_list) return FALSE;
|
||||
/* FIXME: since we likely have a single process, signal the first process
|
||||
* in list
|
||||
*/
|
||||
if (!dbg_process_list) return FALSE;
|
||||
if (dbg_process_list->next) dbg_printf("Ctrl-C: only stopping the first process\n");
|
||||
else dbg_printf("Ctrl-C: stopping debuggee\n");
|
||||
dbg_process_list->continue_on_first_exception = FALSE;
|
||||
return DebugBreakProcess(dbg_process_list);
|
||||
return DebugBreakProcess(dbg_process_list->handle);
|
||||
}
|
||||
|
||||
static BOOL WINAPI ctrl_c_handler(DWORD dwCtrlType)
|
||||
|
Loading…
x
Reference in New Issue
Block a user