- 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:
Eric Pouech 2004-09-28 02:13:27 +00:00 committed by Alexandre Julliard
parent 75e02e9335
commit 5fe480b472
11 changed files with 162 additions and 114 deletions

View File

@ -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>

View File

@ -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;
}

View File

@ -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
*/

View File

@ -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);

View File

@ -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));

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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))

View File

@ -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)