/*********************************************************************** * break_add_break_from_lvalue * * Add a breakpoint. */ BOOL break_add_break_from_lvalue(const struct dbg_lvalue* lvalue, BOOL swbp) { ADDRESS64 addr; types_extract_as_address(lvalue, &addr); if (!break_add_break(&addr, TRUE, swbp)) { if (!DBG_IVAR(CanDeferOnBPByAddr)) { dbg_printf("Invalid address, can't set breakpoint\n" "You can turn on deferring bp by address by setting $CanDeferOnBPByAddr to 1\n"); return FALSE; } dbg_printf("Unable to add breakpoint, will check again any time a new DLL is loaded\n"); dbg_curr_process->delayed_bp = dbg_heap_realloc(dbg_curr_process->delayed_bp, sizeof(struct dbg_delayed_bp) * ++dbg_curr_process->num_delayed_bp); dbg_curr_process->delayed_bp[dbg_curr_process->num_delayed_bp - 1].is_symbol = FALSE; dbg_curr_process->delayed_bp[dbg_curr_process->num_delayed_bp - 1].software_bp = swbp; dbg_curr_process->delayed_bp[dbg_curr_process->num_delayed_bp - 1].u.addr = addr; return TRUE; } return FALSE; }
static unsigned dbg_start_debuggee(LPSTR cmdLine) { PROCESS_INFORMATION info; STARTUPINFOA startup, current; DWORD flags; GetStartupInfoA(¤t); memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = (current.dwFlags & STARTF_USESHOWWINDOW) ? current.wShowWindow : SW_SHOWNORMAL; /* FIXME: shouldn't need the CREATE_NEW_CONSOLE, but as usual CUI:s need it * while GUI:s don't */ flags = DEBUG_PROCESS | CREATE_NEW_CONSOLE; if (!DBG_IVAR(AlsoDebugProcChild)) flags |= DEBUG_ONLY_THIS_PROCESS; if (!CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, flags, 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(&be_process_active_io, dbg_curr_pid, 0))) return FALSE; dbg_curr_process->active_debuggee = TRUE; return TRUE; }
static void dbg_init_current_thread(void* start) { if (start) { if (dbg_curr_process->threads && !dbg_curr_process->threads->next && /* first thread ? */ DBG_IVAR(BreakAllThreadsStartup)) { ADDRESS64 addr; break_set_xpoints(FALSE); addr.Mode = AddrModeFlat; addr.Offset = (DWORD_PTR)start; break_add_break(&addr, TRUE, TRUE); break_set_xpoints(TRUE); } } }
int main(int argc, char** argv) { int retv = 0; HANDLE hFile = INVALID_HANDLE_VALUE; enum dbg_start ds; #ifdef __i386__ be_cpu = &be_i386; #elif defined(__powerpc__) be_cpu = &be_ppc; #elif defined(__ALPHA__) be_cpu = &be_alpha; #elif defined(__x86_64__) be_cpu = &be_x86_64; #elif defined(__sparc__) be_cpu = &be_sparc; #elif defined(__arm__) be_cpu = &be_arm; #else # error CPU unknown #endif /* Initialize the output */ dbg_houtput = GetStdHandle(STD_OUTPUT_HANDLE); /* Initialize internal vars */ if (!dbg_load_internal_vars()) return -1; /* as we don't care about exec name */ argc--; argv++; if (argc && !strcmp(argv[0], "--help")) return dbg_winedbg_usage(TRUE); if (argc && !strcmp(argv[0], "--gdb")) { retv = gdb_main(argc, argv); if (retv == -1) dbg_winedbg_usage(FALSE); return retv; } dbg_init_console(); SymSetOptions((SymGetOptions() & ~(SYMOPT_UNDNAME)) | SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_AUTO_PUBLICS); if (argc && (!strcmp(argv[0], "--auto") || !strcmp(argv[0], "--minidump"))) { /* force some internal variables */ DBG_IVAR(BreakOnDllLoad) = 0; dbg_houtput = GetStdHandle(STD_ERROR_HANDLE); switch (dbg_active_auto(argc, argv)) { case start_ok: return 0; case start_error_parse: return dbg_winedbg_usage(FALSE); case start_error_init: return -1; } } /* parse options */ while (argc > 0 && argv[0][0] == '-') { if (!strcmp(argv[0], "--command")) { argc--; argv++; hFile = parser_generate_command_file(argv[0], NULL); if (hFile == INVALID_HANDLE_VALUE) { dbg_printf("Couldn't open temp file (%u)\n", GetLastError()); return 1; } argc--; argv++; continue; } if (!strcmp(argv[0], "--file")) { argc--; argv++; hFile = CreateFileA(argv[0], GENERIC_READ|DELETE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) { dbg_printf("Couldn't open file %s (%u)\n", argv[0], GetLastError()); return 1; } argc--; argv++; continue; } if (!strcmp(argv[0], "--")) { argc--; argv++; break; } return dbg_winedbg_usage(FALSE); } if (!argc) ds = start_ok; else if ((ds = dbg_active_attach(argc, argv)) == start_error_parse && (ds = minidump_reload(argc, argv)) == start_error_parse) ds = dbg_active_launch(argc, argv); switch (ds) { case start_ok: break; case start_error_parse: return dbg_winedbg_usage(FALSE); case start_error_init: return -1; } dbg_start_interactive(hFile); return 0; }
static unsigned dbg_handle_debug_event(DEBUG_EVENT* de) { union { char bufferA[256]; WCHAR buffer[256]; } u; DWORD cont = DBG_CONTINUE; dbg_curr_pid = de->dwProcessId; dbg_curr_tid = de->dwThreadId; if ((dbg_curr_process = dbg_get_process(de->dwProcessId)) != NULL) dbg_curr_thread = dbg_get_thread(dbg_curr_process, de->dwThreadId); else dbg_curr_thread = NULL; switch (de->dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: if (!dbg_curr_thread) { WINE_ERR("%04x:%04x: not a registered process or thread (perhaps a 16 bit one ?)\n", de->dwProcessId, de->dwThreadId); break; } WINE_TRACE("%04x:%04x: exception code=%08x\n", de->dwProcessId, de->dwThreadId, de->u.Exception.ExceptionRecord.ExceptionCode); if (dbg_curr_process->continue_on_first_exception) { 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); if (cont && dbg_curr_thread) { SetThreadContext(dbg_curr_thread->handle, &dbg_context); } } break; case CREATE_PROCESS_DEBUG_EVENT: dbg_curr_process = dbg_add_process(&be_process_active_io, de->dwProcessId, de->u.CreateProcessInfo.hProcess); if (dbg_curr_process == NULL) { WINE_ERR("Couldn't create process\n"); break; } fetch_module_name(de->u.CreateProcessInfo.lpImageName, de->u.CreateProcessInfo.fUnicode, de->u.CreateProcessInfo.lpBaseOfImage, u.buffer, sizeof(u.buffer) / sizeof(WCHAR), TRUE); WINE_TRACE("%04x:%04x: create process '%s'/%p @%p (%u<%u>)\n", de->dwProcessId, de->dwThreadId, wine_dbgstr_w(u.buffer), de->u.CreateProcessInfo.lpImageName, de->u.CreateProcessInfo.lpStartAddress, de->u.CreateProcessInfo.dwDebugInfoFileOffset, de->u.CreateProcessInfo.nDebugInfoSize); dbg_set_process_name(dbg_curr_process, u.buffer); if (!dbg_init(dbg_curr_process->handle, u.buffer, FALSE)) dbg_printf("Couldn't initiate DbgHelp\n"); if (!dbg_load_module(dbg_curr_process->handle, de->u.CreateProcessInfo.hFile, u.buffer, (DWORD_PTR)de->u.CreateProcessInfo.lpBaseOfImage, 0)) dbg_printf("couldn't load main module (%u)\n", GetLastError()); WINE_TRACE("%04x:%04x: create thread I @%p\n", de->dwProcessId, de->dwThreadId, de->u.CreateProcessInfo.lpStartAddress); dbg_curr_thread = dbg_add_thread(dbg_curr_process, de->dwThreadId, de->u.CreateProcessInfo.hThread, de->u.CreateProcessInfo.lpThreadLocalBase); if (!dbg_curr_thread) { WINE_ERR("Couldn't create thread\n"); break; } dbg_init_current_process(); dbg_init_current_thread(de->u.CreateProcessInfo.lpStartAddress); break; case EXIT_PROCESS_DEBUG_EVENT: WINE_TRACE("%04x:%04x: exit process (%d)\n", de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode); if (dbg_curr_process == NULL) { WINE_ERR("Unknown process\n"); break; } tgt_process_active_close_process(dbg_curr_process, FALSE); dbg_printf("Process of pid=%04x has terminated\n", de->dwProcessId); break; case CREATE_THREAD_DEBUG_EVENT: WINE_TRACE("%04x:%04x: create thread D @%p\n", de->dwProcessId, de->dwThreadId, de->u.CreateThread.lpStartAddress); if (dbg_curr_process == NULL) { WINE_ERR("Unknown process\n"); break; } if (dbg_get_thread(dbg_curr_process, de->dwThreadId) != NULL) { WINE_TRACE("Thread already listed, skipping\n"); break; } dbg_curr_thread = dbg_add_thread(dbg_curr_process, de->dwThreadId, de->u.CreateThread.hThread, de->u.CreateThread.lpThreadLocalBase); if (!dbg_curr_thread) { WINE_ERR("Couldn't create thread\n"); break; } dbg_init_current_thread(de->u.CreateThread.lpStartAddress); break; case EXIT_THREAD_DEBUG_EVENT: WINE_TRACE("%04x:%04x: exit thread (%d)\n", de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode); if (dbg_curr_thread == NULL) { WINE_ERR("Unknown thread\n"); break; } /* FIXME: remove break point set on thread startup */ dbg_del_thread(dbg_curr_thread); break; case LOAD_DLL_DEBUG_EVENT: if (dbg_curr_thread == NULL) { WINE_ERR("Unknown thread\n"); break; } fetch_module_name(de->u.LoadDll.lpImageName, de->u.LoadDll.fUnicode, de->u.LoadDll.lpBaseOfDll, u.buffer, sizeof(u.buffer) / sizeof(WCHAR), FALSE); WINE_TRACE("%04x:%04x: loads DLL %s @%p (%u<%u>)\n", de->dwProcessId, de->dwThreadId, wine_dbgstr_w(u.buffer), de->u.LoadDll.lpBaseOfDll, de->u.LoadDll.dwDebugInfoFileOffset, de->u.LoadDll.nDebugInfoSize); dbg_load_module(dbg_curr_process->handle, de->u.LoadDll.hFile, u.buffer, (DWORD_PTR)de->u.LoadDll.lpBaseOfDll, 0); break_set_xpoints(FALSE); break_check_delayed_bp(); break_set_xpoints(TRUE); if (DBG_IVAR(BreakOnDllLoad)) { dbg_printf("Stopping on DLL %s loading at 0x%08lx\n", dbg_W2A(u.buffer, -1), (unsigned long)de->u.LoadDll.lpBaseOfDll); if (dbg_fetch_context()) cont = 0; } break; case UNLOAD_DLL_DEBUG_EVENT: WINE_TRACE("%04x:%04x: unload DLL @%p\n", de->dwProcessId, de->dwThreadId, de->u.UnloadDll.lpBaseOfDll); break_delete_xpoints_from_module((unsigned long)de->u.UnloadDll.lpBaseOfDll); SymUnloadModule(dbg_curr_process->handle, (unsigned long)de->u.UnloadDll.lpBaseOfDll); break; case OUTPUT_DEBUG_STRING_EVENT: if (dbg_curr_thread == NULL) { WINE_ERR("Unknown thread\n"); break; } memory_get_string(dbg_curr_process, de->u.DebugString.lpDebugStringData, TRUE, de->u.DebugString.fUnicode, u.bufferA, sizeof(u.bufferA)); WINE_TRACE("%04x:%04x: output debug string (%s)\n", de->dwProcessId, de->dwThreadId, u.bufferA); break; case RIP_EVENT: WINE_TRACE("%04x:%04x: rip error=%u type=%u\n", de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError, de->u.RipInfo.dwType); break; default: WINE_TRACE("%04x:%04x: unknown event (%x)\n", de->dwProcessId, de->dwThreadId, de->dwDebugEventCode); } if (!cont) return TRUE; /* stop execution */ ContinueDebugEvent(de->dwProcessId, de->dwThreadId, cont); return FALSE; /* continue execution */ }
static DWORD dbg_handle_exception(const EXCEPTION_RECORD* rec, BOOL first_chance) { BOOL is_debug = FALSE; THREADNAME_INFO* pThreadName; struct dbg_thread* pThread; assert(dbg_curr_thread); WINE_TRACE("exception=%x first_chance=%c\n", rec->ExceptionCode, first_chance ? 'Y' : 'N'); switch (rec->ExceptionCode) { case EXCEPTION_BREAKPOINT: case EXCEPTION_SINGLE_STEP: is_debug = TRUE; break; case EXCEPTION_NAME_THREAD: pThreadName = (THREADNAME_INFO*)(rec->ExceptionInformation); if (pThreadName->dwThreadID == -1) pThread = dbg_curr_thread; else pThread = dbg_get_thread(dbg_curr_process, pThreadName->dwThreadID); if(!pThread) { dbg_printf("Thread ID=%04x not in our list of threads -> can't rename\n", pThreadName->dwThreadID); return DBG_CONTINUE; } if (dbg_read_memory(pThreadName->szName, pThread->name, 9)) dbg_printf("Thread ID=%04x renamed using MS VC6 extension (name==\"%s\")\n", pThread->tid, pThread->name); return DBG_CONTINUE; } if (first_chance && !is_debug && !DBG_IVAR(BreakOnFirstChance) && !(rec->ExceptionFlags & EH_STACK_INVALID)) { /* pass exception to program except for debug exceptions */ return DBG_EXCEPTION_NOT_HANDLED; } if (!is_debug) { /* print some infos */ dbg_printf("%s: ", first_chance ? "First chance exception" : "Unhandled exception"); switch (rec->ExceptionCode) { case EXCEPTION_INT_DIVIDE_BY_ZERO: dbg_printf("divide by zero"); break; case EXCEPTION_INT_OVERFLOW: dbg_printf("overflow"); break; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: dbg_printf("array bounds"); break; case EXCEPTION_ILLEGAL_INSTRUCTION: dbg_printf("illegal instruction"); break; case EXCEPTION_STACK_OVERFLOW: dbg_printf("stack overflow"); break; case EXCEPTION_PRIV_INSTRUCTION: dbg_printf("privileged instruction"); break; case EXCEPTION_ACCESS_VIOLATION: if (rec->NumberParameters == 2) dbg_printf("page fault on %s access to 0x%08lx", rec->ExceptionInformation[0] == EXCEPTION_WRITE_FAULT ? "write" : rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT ? "execute" : "read", rec->ExceptionInformation[1]); else dbg_printf("page fault"); break; case EXCEPTION_DATATYPE_MISALIGNMENT: dbg_printf("Alignment"); break; case DBG_CONTROL_C: dbg_printf("^C"); break; case CONTROL_C_EXIT: dbg_printf("^C"); break; case STATUS_POSSIBLE_DEADLOCK: { ADDRESS64 addr; addr.Mode = AddrModeFlat; addr.Offset = rec->ExceptionInformation[0]; dbg_printf("wait failed on critical section "); print_address(&addr, FALSE); } if (!DBG_IVAR(BreakOnCritSectTimeOut)) { dbg_printf("\n"); return DBG_EXCEPTION_NOT_HANDLED; } break; case EXCEPTION_WINE_STUB: { char dll[32], name[64]; memory_get_string(dbg_curr_process, (void*)rec->ExceptionInformation[0], TRUE, FALSE, dll, sizeof(dll)); if (HIWORD(rec->ExceptionInformation[1])) memory_get_string(dbg_curr_process, (void*)rec->ExceptionInformation[1], TRUE, FALSE, name, sizeof(name)); else sprintf( name, "%ld", rec->ExceptionInformation[1] ); dbg_printf("unimplemented function %s.%s called", dll, name); } break; case EXCEPTION_WINE_ASSERTION: dbg_printf("assertion failed"); break; case EXCEPTION_VM86_INTx: dbg_printf("interrupt %02lx in vm86 mode", rec->ExceptionInformation[0]); break; case EXCEPTION_VM86_STI: dbg_printf("sti in vm86 mode"); break; case EXCEPTION_VM86_PICRETURN: dbg_printf("PIC return in vm86 mode"); break; case EXCEPTION_FLT_DENORMAL_OPERAND: dbg_printf("denormal float operand"); break; case EXCEPTION_FLT_DIVIDE_BY_ZERO: dbg_printf("divide by zero"); break; case EXCEPTION_FLT_INEXACT_RESULT: dbg_printf("inexact float result"); break; case EXCEPTION_FLT_INVALID_OPERATION: dbg_printf("invalid float operation"); break; case EXCEPTION_FLT_OVERFLOW: dbg_printf("floating point overflow"); break; case EXCEPTION_FLT_UNDERFLOW: dbg_printf("floating point underflow"); break; case EXCEPTION_FLT_STACK_CHECK: dbg_printf("floating point stack check"); break; case CXX_EXCEPTION: if(rec->NumberParameters == 3 && rec->ExceptionInformation[0] == CXX_FRAME_MAGIC) dbg_printf("C++ exception(object = 0x%08lx, type = 0x%08lx)", rec->ExceptionInformation[1], rec->ExceptionInformation[2]); else dbg_printf("C++ exception with strange parameter count %d or magic 0x%08lx", rec->NumberParameters, rec->ExceptionInformation[0]); break; default: dbg_printf("0x%08x", rec->ExceptionCode); break; } } if( (rec->ExceptionFlags & EH_STACK_INVALID) ) { dbg_printf( ", invalid program stack" ); } if (dbg_exception_prolog(is_debug, first_chance, rec)) { dbg_interactiveP = TRUE; return 0; } dbg_exception_epilog(); return DBG_CONTINUE; }
/*********************************************************************** * symbol_get_lvalue * * Get the address of a named symbol. * Return values: * sglv_found: if the symbol is found * sglv_unknown: if the symbol isn't found * sglv_aborted: some error occurred (likely, many symbols of same name exist, * and user didn't pick one of them) */ enum sym_get_lval symbol_get_lvalue(const char* name, const int lineno, struct dbg_lvalue* rtn, BOOL bp_disp) { struct sgv_data sgv; int i; char buffer[512]; DWORD opt; IMAGEHLP_STACK_FRAME ihsf; if (strlen(name) + 4 > sizeof(buffer)) { WINE_WARN("Too long symbol (%s)\n", name); return sglv_unknown; } sgv.num = 0; sgv.num_thunks = 0; sgv.name = &buffer[2]; sgv.do_thunks = DBG_IVAR(AlwaysShowThunks); if (strchr(name, '!')) { strcpy(buffer, name); } else { buffer[0] = '*'; buffer[1] = '!'; strcpy(&buffer[2], name); } /* this is a wine specific options to return also ELF modules in the * enumeration */ SymSetOptions((opt = SymGetOptions()) | 0x40000000); SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv); if (!sgv.num) { const char* ptr = strchr(name, '!'); if ((ptr && ptr[1] != '_') || (!ptr && *name != '_')) { if (ptr) { int offset = ptr - name; memcpy(buffer, name, offset + 1); buffer[offset + 1] = '_'; strcpy(&buffer[offset + 2], ptr + 1); } else { buffer[0] = '*'; buffer[1] = '!'; buffer[2] = '_'; strcpy(&buffer[3], name); } SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv); } } SymSetOptions(opt); /* now grab local symbols */ if (stack_get_current_frame(&ihsf) && sgv.num < NUMDBGV) { sgv.frame_offset = ihsf.FrameOffset; SymEnumSymbols(dbg_curr_process->handle, 0, name, sgv_cb, (void*)&sgv); } if (!sgv.num) { dbg_printf("No symbols found for %s\n", name); return sglv_unknown; } /* recompute potential offsets for functions (linenumber, skip prolog) */ for (i = 0; i < sgv.num; i++) { if (sgv.syms[i].flags & (SYMFLAG_REGISTER|SYMFLAG_REGREL|SYMFLAG_LOCAL|SYMFLAG_THUNK)) continue; if (lineno == -1) { struct dbg_type type; ULONG64 addr; type.module = sgv.syms[i].lvalue.type.module; type.id = sgv.syms[i].sym_info; if (bp_disp && symbol_get_debug_start(&type, &addr)) sgv.syms[i].lvalue.addr.Offset = addr; } else { DWORD disp; IMAGEHLP_LINE il; BOOL found = FALSE; il.SizeOfStruct = sizeof(il); SymGetLineFromAddr(dbg_curr_process->handle, (DWORD)memory_to_linear_addr(&sgv.syms[i].lvalue.addr), &disp, &il); do { if (lineno == il.LineNumber) { sgv.syms[i].lvalue.addr.Offset = il.Address; found = TRUE; break; } } while (SymGetLineNext(dbg_curr_process->handle, &il)); if (!found) WINE_FIXME("No line (%d) found for %s (setting to symbol start)\n", lineno, name); } } i = 0; if (dbg_interactiveP) { if (sgv.num - sgv.num_thunks > 1 || /* many symbols non thunks (and showing only non thunks) */ (sgv.num > 1 && DBG_IVAR(AlwaysShowThunks)) || /* many symbols (showing symbols & thunks) */ (sgv.num == sgv.num_thunks && sgv.num_thunks > 1)) { dbg_printf("Many symbols with name '%s', " "choose the one you want (<cr> to abort):\n", name); for (i = 0; i < sgv.num; i++) { if (sgv.num - sgv.num_thunks > 1 && (sgv.syms[i].flags & SYMFLAG_THUNK) && !DBG_IVAR(AlwaysShowThunks)) continue; dbg_printf("[%d]: ", i + 1); if (sgv.syms[i].flags & SYMFLAG_LOCAL) { dbg_printf("%s %sof %s\n", sgv.syms[i].flags & SYMFLAG_PARAMETER ? "Parameter" : "Local variable", sgv.syms[i].flags & (SYMFLAG_REGISTER|SYMFLAG_REGREL) ? "(in a register) " : "", name); } else if (sgv.syms[i].flags & SYMFLAG_THUNK) { print_address(&sgv.syms[i].lvalue.addr, TRUE); /* FIXME: should display where the thunks points to */ dbg_printf(" thunk %s\n", name); } else { print_address(&sgv.syms[i].lvalue.addr, TRUE); dbg_printf("\n"); } } do { i = 0; if (input_read_line("=> ", buffer, sizeof(buffer))) { if (buffer[0] == '\0') return sglv_aborted; i = atoi(buffer); if (i < 1 || i > sgv.num) dbg_printf("Invalid choice %d\n", i); } else return sglv_aborted; } while (i < 1 || i > sgv.num); /* The array is 0-based, but the choices are 1..n, * so we have to subtract one before returning. */ i--; } } else { /* FIXME: could display the list of non-picked up symbols */ if (sgv.num > 1) dbg_printf("More than one symbol named %s, picking the first one\n", name); } *rtn = sgv.syms[i].lvalue; return sglv_found; }
/*********************************************************************** * symbol_get_lvalue * * Get the address of a named symbol. * Return values: * sglv_found: if the symbol is found * sglv_unknown: if the symbol isn't found * sglv_aborted: some error occurred (likely, many symbols of same name exist, * and user didn't pick one of them) */ enum sym_get_lval symbol_get_lvalue(const char* name, const int lineno, struct dbg_lvalue* rtn, BOOL bp_disp) { struct sgv_data sgv; int i; char buffer[512]; DWORD opt; IMAGEHLP_STACK_FRAME ihsf; if (strlen(name) + 4 > sizeof(buffer)) { WINE_WARN("Too long symbol (%s)\n", name); return sglv_unknown; } sgv.num = 0; sgv.num_thunks = 0; sgv.name = &buffer[2]; sgv.do_thunks = DBG_IVAR(AlwaysShowThunks); if (strchr(name, '!')) { strcpy(buffer, name); } else { buffer[0] = '*'; buffer[1] = '!'; strcpy(&buffer[2], name); } /* this is a wine specific options to return also ELF modules in the * enumeration */ SymSetOptions((opt = SymGetOptions()) | 0x40000000); SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv); if (!sgv.num) { const char* ptr = strchr(name, '!'); if ((ptr && ptr[1] != '_') || (!ptr && *name != '_')) { if (ptr) { int offset = ptr - name; memcpy(buffer, name, offset + 1); buffer[offset + 1] = '_'; strcpy(&buffer[offset + 2], ptr + 1); } else { buffer[0] = '*'; buffer[1] = '!'; buffer[2] = '_'; strcpy(&buffer[3], name); } SymEnumSymbols(dbg_curr_process->handle, 0, buffer, sgv_cb, (void*)&sgv); } } SymSetOptions(opt); /* now grab local symbols */ if (stack_get_current_frame(&ihsf) && sgv.num < NUMDBGV) { sgv.frame_offset = ihsf.FrameOffset; SymEnumSymbols(dbg_curr_process->handle, 0, name, sgv_cb, (void*)&sgv); } if (!sgv.num) { dbg_printf("No symbols found for %s\n", name); return sglv_unknown; } /* recompute potential offsets for functions (linenumber, skip prolog) */ for (i = 0; i < sgv.num; i++) { if (sgv.syms[i].flags & (SYMFLAG_REGISTER|SYMFLAG_REGREL|SYMFLAG_LOCAL|SYMFLAG_THUNK)) continue; if (lineno == -1) { struct dbg_type type; ULONG64 addr; type.module = sgv.syms[i].lvalue.type.module; type.id = sgv.syms[i].sym_info; if (bp_disp && symbol_get_debug_start(&type, &addr)) sgv.syms[i].lvalue.addr.Offset = addr; } else { DWORD disp; IMAGEHLP_LINE64 il; BOOL found = FALSE; il.SizeOfStruct = sizeof(il); SymGetLineFromAddr64(dbg_curr_process->handle, (DWORD_PTR)memory_to_linear_addr(&sgv.syms[i].lvalue.addr), &disp, &il); do { if (lineno == il.LineNumber) { sgv.syms[i].lvalue.addr.Offset = il.Address; found = TRUE; break; } } while (SymGetLineNext64(dbg_curr_process->handle, &il)); if (!found) WINE_FIXME("No line (%d) found for %s (setting to symbol start)\n", lineno, name); } } if (sgv.num - sgv.num_thunks > 1 || /* many symbols non thunks (and showing only non thunks) */ (sgv.num > 1 && DBG_IVAR(AlwaysShowThunks)) || /* many symbols (showing symbols & thunks) */ (sgv.num == sgv.num_thunks && sgv.num_thunks > 1)) { return symbol_current_picker(name, &sgv, rtn); } /* first symbol is the one we want: * - only one symbol found, * - or many symbols but only one non thunk when AlwaysShowThunks is FALSE */ *rtn = sgv.syms[0].lvalue; return sglv_found; }
enum sym_get_lval symbol_picker_scoped(const char* name, const struct sgv_data* sgv, struct dbg_lvalue* rtn) { unsigned i; int local = -1; for (i = 0; i < sgv->num; i++) { if (sgv->num - sgv->num_thunks > 1 && (sgv->syms[i].flags & SYMFLAG_THUNK) && !DBG_IVAR(AlwaysShowThunks)) continue; if (sgv->syms[i].flags & (SYMFLAG_LOCAL | SYMFLAG_PARAMETER)) { if (local == -1) local = i; else { /* FIXME: several locals with same name... which one to pick ?? */ dbg_printf("Several local variables/parameters for %s, aborting\n", name); return sglv_aborted; } } } if (local != -1) { *rtn = sgv->syms[local].lvalue; return sglv_found; } /* no locals found, multiple globals... abort for now */ dbg_printf("Several global variables for %s, aborting\n", name); return sglv_aborted; }
enum sym_get_lval symbol_picker_interactive(const char* name, const struct sgv_data* sgv, struct dbg_lvalue* rtn) { char buffer[512]; unsigned i; if (!dbg_interactiveP) { dbg_printf("More than one symbol named %s, picking the first one\n", name); *rtn = sgv->syms[0].lvalue; return sglv_found; } dbg_printf("Many symbols with name '%s', " "choose the one you want (<cr> to abort):\n", name); for (i = 0; i < sgv->num; i++) { if (sgv->num - sgv->num_thunks > 1 && (sgv->syms[i].flags & SYMFLAG_THUNK) && !DBG_IVAR(AlwaysShowThunks)) continue; dbg_printf("[%d]: ", i + 1); if (sgv->syms[i].flags & (SYMFLAG_LOCAL | SYMFLAG_PARAMETER)) { dbg_printf("%s %sof %s\n", sgv->syms[i].flags & SYMFLAG_PARAMETER ? "Parameter" : "Local variable", sgv->syms[i].flags & (SYMFLAG_REGISTER|SYMFLAG_REGREL) ? "(in a register) " : "", name); } else if (sgv->syms[i].flags & SYMFLAG_THUNK) { print_address(&sgv->syms[i].lvalue.addr, TRUE); /* FIXME: should display where the thunks points to */ dbg_printf(" thunk %s\n", name); } else { print_address(&sgv->syms[i].lvalue.addr, TRUE); dbg_printf("\n"); } } do { if (input_read_line("=> ", buffer, sizeof(buffer))) { if (buffer[0] == '\0') return sglv_aborted; i = atoi(buffer); if (i < 1 || i > sgv->num) dbg_printf("Invalid choice %d\n", i); } else return sglv_aborted; } while (i < 1 || i > sgv->num); /* The array is 0-based, but the choices are 1..n, * so we have to subtract one before returning. */ *rtn = sgv->syms[i - 1].lvalue; return sglv_found; }