winedbg.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721
  1. /* Wine internal debugger
  2. * Interface to Windows debugger API
  3. * Copyright 2000-2004 Eric Pouech
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2.1 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  18. */
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include "debugger.h"
  23. #include "winternl.h"
  24. #include "wine/debug.h"
  25. /* TODO list:
  26. *
  27. * - minidump
  28. * + ensure that all commands work as expected in minidump reload function
  29. * (and re-enable parser usage)
  30. * - CPU adherence
  31. * + we always assume the stack grows as on i386 (i.e. downwards)
  32. * - UI
  33. * + re-enable the limited output (depth of structure printing and number of
  34. * lines)
  35. * + make the output as close as possible to what gdb does
  36. * - symbol management:
  37. * + symbol table loading is broken
  38. * + in symbol_get_lvalue, we don't do any scoping (as C does) between local and
  39. * global vars (we may need this to force some display for example). A solution
  40. * would be always to return arrays with: local vars, global vars, thunks
  41. * - type management:
  42. * + some bits of internal types are missing (like type casts and the address
  43. * operator)
  44. * + all computations should be made on 64bit
  45. * o bitfield spreading on more bytes than dbg_lgint_t isn't supported
  46. * (can happen on 128bit integers, of an ELF build...)
  47. * - execution:
  48. * + set a better fix for gdb (proxy mode) than the step-mode hack
  49. * + implement function call in debuggee
  50. * + trampoline management is broken when getting 16 <=> 32 thunk destination
  51. * address
  52. * + thunking of delayed imports doesn't work as expected (ie, when stepping,
  53. * it currently stops at first insn with line number during the library
  54. * loading). We should identify this (__wine_delay_import) and set a
  55. * breakpoint instead of single stepping the library loading.
  56. * + it's wrong to copy thread->step_over_bp into process->bp[0] (when
  57. * we have a multi-thread debuggee). complete fix must include storing all
  58. * thread's step-over bp in process-wide bp array, and not to handle bp
  59. * when we have the wrong thread running into that bp
  60. * + code in CREATE_PROCESS debug event doesn't work on Windows, as we cannot
  61. * get the name of the main module this way. We should rewrite all this code
  62. * and store in struct dbg_process as early as possible (before process
  63. * creation or attachment), the name of the main module
  64. * - global:
  65. * + define a better way to enable the wine extensions (either DBG SDK function
  66. * in dbghelp, or TLS variable, or environment variable or ...)
  67. * + audit all files to ensure that we check all potential return values from
  68. * every function call to catch the errors
  69. * + BTW check also whether the exception mechanism is the best way to return
  70. * errors (or find a proper fix for MinGW port)
  71. */
  72. WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
  73. struct dbg_process* dbg_curr_process = NULL;
  74. struct dbg_thread* dbg_curr_thread = NULL;
  75. DWORD dbg_curr_tid = 0;
  76. DWORD dbg_curr_pid = 0;
  77. dbg_ctx_t dbg_context;
  78. BOOL dbg_interactiveP = FALSE;
  79. HANDLE dbg_houtput = 0;
  80. static struct list dbg_process_list = LIST_INIT(dbg_process_list);
  81. struct dbg_internal_var dbg_internal_vars[DBG_IV_LAST];
  82. static void dbg_outputA(const char* buffer, int len)
  83. {
  84. static char line_buff[4096];
  85. static unsigned int line_pos;
  86. DWORD w, i;
  87. while (len > 0)
  88. {
  89. unsigned int count = min( len, sizeof(line_buff) - line_pos );
  90. memcpy( line_buff + line_pos, buffer, count );
  91. buffer += count;
  92. len -= count;
  93. line_pos += count;
  94. for (i = line_pos; i > 0; i--) if (line_buff[i-1] == '\n') break;
  95. if (!i) /* no newline found */
  96. {
  97. if (len > 0) i = line_pos; /* buffer is full, flush anyway */
  98. else break;
  99. }
  100. WriteFile(dbg_houtput, line_buff, i, &w, NULL);
  101. memmove( line_buff, line_buff + i, line_pos - i );
  102. line_pos -= i;
  103. }
  104. }
  105. int WINAPIV dbg_printf(const char* format, ...)
  106. {
  107. static char buf[4*1024];
  108. va_list valist;
  109. int len;
  110. va_start(valist, format);
  111. len = vsnprintf(buf, sizeof(buf), format, valist);
  112. va_end(valist);
  113. if (len <= -1 || len >= sizeof(buf))
  114. {
  115. len = sizeof(buf) - 1;
  116. buf[len] = 0;
  117. buf[len - 1] = buf[len - 2] = buf[len - 3] = '.';
  118. }
  119. dbg_outputA(buf, len);
  120. return len;
  121. }
  122. static unsigned dbg_load_internal_vars(void)
  123. {
  124. HKEY hkey;
  125. DWORD type = REG_DWORD;
  126. DWORD val;
  127. DWORD count = sizeof(val);
  128. int i;
  129. struct dbg_internal_var* div = dbg_internal_vars;
  130. /* initializes internal vars table */
  131. #define INTERNAL_VAR(_var,_val,_ref,_tid) \
  132. div->val = _val; div->name = #_var; div->pval = _ref; \
  133. div->typeid = _tid; div++;
  134. #include "intvar.h"
  135. #undef INTERNAL_VAR
  136. /* @@ Wine registry key: HKCU\Software\Wine\WineDbg */
  137. if (RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\WineDbg", &hkey))
  138. {
  139. WINE_ERR("Cannot create WineDbg key in registry\n");
  140. return FALSE;
  141. }
  142. for (i = 0; i < DBG_IV_LAST; i++)
  143. {
  144. if (!dbg_internal_vars[i].pval)
  145. {
  146. if (!RegQueryValueExA(hkey, dbg_internal_vars[i].name, 0,
  147. &type, (LPBYTE)&val, &count))
  148. dbg_internal_vars[i].val = val;
  149. dbg_internal_vars[i].pval = &dbg_internal_vars[i].val;
  150. }
  151. }
  152. RegCloseKey(hkey);
  153. return TRUE;
  154. }
  155. static unsigned dbg_save_internal_vars(void)
  156. {
  157. HKEY hkey;
  158. int i;
  159. /* @@ Wine registry key: HKCU\Software\Wine\WineDbg */
  160. if (RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\WineDbg", &hkey))
  161. {
  162. WINE_ERR("Cannot create WineDbg key in registry\n");
  163. return FALSE;
  164. }
  165. for (i = 0; i < DBG_IV_LAST; i++)
  166. {
  167. /* FIXME: type should be inferred from basic type -if any- of intvar */
  168. if (dbg_internal_vars[i].pval == &dbg_internal_vars[i].val)
  169. {
  170. DWORD val = dbg_internal_vars[i].val;
  171. RegSetValueExA(hkey, dbg_internal_vars[i].name, 0, REG_DWORD, (BYTE *)&val, sizeof(val));
  172. }
  173. }
  174. RegCloseKey(hkey);
  175. return TRUE;
  176. }
  177. const struct dbg_internal_var* dbg_get_internal_var(const char* name)
  178. {
  179. const struct dbg_internal_var* div;
  180. for (div = &dbg_internal_vars[DBG_IV_LAST - 1]; div >= dbg_internal_vars; div--)
  181. {
  182. if (!strcmp(div->name, name)) return div;
  183. }
  184. for (div = dbg_curr_process->be_cpu->context_vars; div->name; div++)
  185. {
  186. if (!strcasecmp(div->name, name))
  187. {
  188. struct dbg_internal_var* ret = (void*)lexeme_alloc_size(sizeof(*ret));
  189. /* relocate register's field against current context */
  190. *ret = *div;
  191. ret->pval = (char*)&dbg_context + (DWORD_PTR)div->pval;
  192. return ret;
  193. }
  194. }
  195. return NULL;
  196. }
  197. unsigned dbg_num_processes(void)
  198. {
  199. return list_count(&dbg_process_list);
  200. }
  201. struct dbg_process* dbg_get_process(DWORD pid)
  202. {
  203. struct dbg_process* p;
  204. LIST_FOR_EACH_ENTRY(p, &dbg_process_list, struct dbg_process, entry)
  205. if (p->pid == pid) return p;
  206. return NULL;
  207. }
  208. struct dbg_process* dbg_get_process_h(HANDLE h)
  209. {
  210. struct dbg_process* p;
  211. LIST_FOR_EACH_ENTRY(p, &dbg_process_list, struct dbg_process, entry)
  212. if (p->handle == h) return p;
  213. return NULL;
  214. }
  215. #ifdef __i386__
  216. extern struct backend_cpu be_i386;
  217. #elif defined(__x86_64__)
  218. extern struct backend_cpu be_i386;
  219. extern struct backend_cpu be_x86_64;
  220. #elif defined(__arm__) && !defined(__ARMEB__)
  221. extern struct backend_cpu be_arm;
  222. #elif defined(__aarch64__) && !defined(__AARCH64EB__)
  223. extern struct backend_cpu be_arm64;
  224. #else
  225. # error CPU unknown
  226. #endif
  227. struct dbg_process* dbg_add_process(const struct be_process_io* pio, DWORD pid, HANDLE h)
  228. {
  229. struct dbg_process* p;
  230. BOOL wow64;
  231. if ((p = dbg_get_process(pid)))
  232. return p;
  233. if (!h)
  234. h = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
  235. if (!(p = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_process)))) return NULL;
  236. p->handle = h;
  237. p->pid = pid;
  238. p->process_io = pio;
  239. p->pio_data = NULL;
  240. p->imageName = NULL;
  241. list_init(&p->threads);
  242. p->event_on_first_exception = NULL;
  243. p->active_debuggee = FALSE;
  244. p->next_bp = 1; /* breakpoint 0 is reserved for step-over */
  245. memset(p->bp, 0, sizeof(p->bp));
  246. p->delayed_bp = NULL;
  247. p->num_delayed_bp = 0;
  248. p->source_ofiles = NULL;
  249. p->search_path = NULL;
  250. p->source_current_file[0] = '\0';
  251. p->source_start_line = -1;
  252. p->source_end_line = -1;
  253. p->data_model = NULL;
  254. list_add_head(&dbg_process_list, &p->entry);
  255. IsWow64Process(h, &wow64);
  256. #ifdef __i386__
  257. p->be_cpu = &be_i386;
  258. #elif defined(__x86_64__)
  259. p->be_cpu = wow64 ? &be_i386 : &be_x86_64;
  260. #elif defined(__arm__) && !defined(__ARMEB__)
  261. p->be_cpu = &be_arm;
  262. #elif defined(__aarch64__) && !defined(__AARCH64EB__)
  263. p->be_cpu = &be_arm64;
  264. #else
  265. # error CPU unknown
  266. #endif
  267. return p;
  268. }
  269. void dbg_set_process_name(struct dbg_process* p, const WCHAR* imageName)
  270. {
  271. assert(p->imageName == NULL);
  272. if (imageName)
  273. {
  274. WCHAR* tmp = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(imageName) + 1) * sizeof(WCHAR));
  275. if (tmp) p->imageName = lstrcpyW(tmp, imageName);
  276. }
  277. }
  278. void dbg_del_process(struct dbg_process* p)
  279. {
  280. struct dbg_thread* t;
  281. struct dbg_thread* t2;
  282. int i;
  283. LIST_FOR_EACH_ENTRY_SAFE(t, t2, &p->threads, struct dbg_thread, entry)
  284. dbg_del_thread(t);
  285. for (i = 0; i < p->num_delayed_bp; i++)
  286. if (p->delayed_bp[i].is_symbol)
  287. HeapFree(GetProcessHeap(), 0, p->delayed_bp[i].u.symbol.name);
  288. HeapFree(GetProcessHeap(), 0, p->delayed_bp);
  289. source_nuke_path(p);
  290. source_free_files(p);
  291. list_remove(&p->entry);
  292. if (p == dbg_curr_process) dbg_curr_process = NULL;
  293. if (p->event_on_first_exception) CloseHandle(p->event_on_first_exception);
  294. HeapFree(GetProcessHeap(), 0, (char*)p->imageName);
  295. HeapFree(GetProcessHeap(), 0, p);
  296. }
  297. /******************************************************************
  298. * dbg_init
  299. *
  300. * Initializes the dbghelp library, and also sets the application directory
  301. * as a place holder for symbol searches.
  302. */
  303. BOOL dbg_init(HANDLE hProc, const WCHAR* in, BOOL invade)
  304. {
  305. BOOL ret;
  306. ret = SymInitialize(hProc, NULL, invade);
  307. if (ret && in)
  308. {
  309. const WCHAR* last;
  310. for (last = in + lstrlenW(in) - 1; last >= in; last--)
  311. {
  312. if (*last == '/' || *last == '\\')
  313. {
  314. WCHAR* tmp;
  315. tmp = HeapAlloc(GetProcessHeap(), 0, (1024 + 1 + (last - in) + 1) * sizeof(WCHAR));
  316. if (tmp && SymGetSearchPathW(hProc, tmp, 1024))
  317. {
  318. WCHAR* x = tmp + lstrlenW(tmp);
  319. *x++ = ';';
  320. memcpy(x, in, (last - in) * sizeof(WCHAR));
  321. x[last - in] = '\0';
  322. ret = SymSetSearchPathW(hProc, tmp);
  323. }
  324. else ret = FALSE;
  325. HeapFree(GetProcessHeap(), 0, tmp);
  326. break;
  327. }
  328. }
  329. }
  330. return ret;
  331. }
  332. BOOL dbg_load_module(HANDLE hProc, HANDLE hFile, const WCHAR* name, DWORD_PTR base, DWORD size)
  333. {
  334. BOOL ret = SymLoadModuleExW(hProc, NULL, name, NULL, base, size, NULL, 0);
  335. if (ret)
  336. {
  337. IMAGEHLP_MODULEW64 ihm;
  338. ihm.SizeOfStruct = sizeof(ihm);
  339. if (SymGetModuleInfoW64(hProc, base, &ihm) && (ihm.PdbUnmatched || ihm.DbgUnmatched))
  340. dbg_printf("Loaded unmatched debug information for %s\n", wine_dbgstr_w(name));
  341. }
  342. return ret;
  343. }
  344. struct dbg_thread* dbg_get_thread(struct dbg_process* p, DWORD tid)
  345. {
  346. struct dbg_thread* t;
  347. if (!p) return NULL;
  348. LIST_FOR_EACH_ENTRY(t, &p->threads, struct dbg_thread, entry)
  349. if (t->tid == tid) return t;
  350. return NULL;
  351. }
  352. struct dbg_thread* dbg_add_thread(struct dbg_process* p, DWORD tid,
  353. HANDLE h, void* teb)
  354. {
  355. struct dbg_thread* t = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dbg_thread));
  356. if (!t)
  357. return NULL;
  358. t->handle = h;
  359. t->tid = tid;
  360. t->teb = teb;
  361. t->process = p;
  362. t->exec_mode = dbg_exec_cont;
  363. t->exec_count = 0;
  364. t->step_over_bp.enabled = FALSE;
  365. t->step_over_bp.refcount = 0;
  366. t->stopped_xpoint = -1;
  367. t->name[0] = '\0';
  368. t->in_exception = FALSE;
  369. t->frames = NULL;
  370. t->num_frames = 0;
  371. t->curr_frame = -1;
  372. t->addr_mode = AddrModeFlat;
  373. t->suspended = FALSE;
  374. list_add_head(&p->threads, &t->entry);
  375. return t;
  376. }
  377. void dbg_del_thread(struct dbg_thread* t)
  378. {
  379. HeapFree(GetProcessHeap(), 0, t->frames);
  380. list_remove(&t->entry);
  381. if (t == dbg_curr_thread) dbg_curr_thread = NULL;
  382. HeapFree(GetProcessHeap(), 0, t);
  383. }
  384. void dbg_set_option(const char* option, const char* val)
  385. {
  386. if (!strcasecmp(option, "module_load_mismatched"))
  387. {
  388. DWORD opt = SymGetOptions();
  389. if (!val)
  390. dbg_printf("Option: module_load_mismatched %s\n", opt & SYMOPT_LOAD_ANYTHING ? "true" : "false");
  391. else if (!strcasecmp(val, "true")) opt |= SYMOPT_LOAD_ANYTHING;
  392. else if (!strcasecmp(val, "false")) opt &= ~SYMOPT_LOAD_ANYTHING;
  393. else
  394. {
  395. dbg_printf("Syntax: module_load_mismatched [true|false]\n");
  396. return;
  397. }
  398. SymSetOptions(opt);
  399. }
  400. else if (!strcasecmp(option, "symbol_picker"))
  401. {
  402. if (!val)
  403. dbg_printf("Option: symbol_picker %s\n",
  404. symbol_current_picker == symbol_picker_interactive ? "interactive" : "scoped");
  405. else if (!strcasecmp(val, "interactive"))
  406. symbol_current_picker = symbol_picker_interactive;
  407. else if (!strcasecmp(val, "scoped"))
  408. symbol_current_picker = symbol_picker_scoped;
  409. else
  410. {
  411. dbg_printf("Syntax: symbol_picker [interactive|scoped]\n");
  412. return;
  413. }
  414. }
  415. else if (!strcasecmp(option, "data_model"))
  416. {
  417. if (!dbg_curr_process)
  418. {
  419. dbg_printf("Not attached to a process\n");
  420. return;
  421. }
  422. if (!val)
  423. {
  424. const char* model = "";
  425. if (dbg_curr_process->data_model == NULL) model = "auto";
  426. else if (dbg_curr_process->data_model == ilp32_data_model) model = "ilp32";
  427. else if (dbg_curr_process->data_model == llp64_data_model) model = "llp64";
  428. else if (dbg_curr_process->data_model == lp64_data_model) model = "lp64";
  429. dbg_printf("Option: data_model %s\n", model);
  430. }
  431. else if (!strcasecmp(val, "auto")) dbg_curr_process->data_model = NULL;
  432. else if (!strcasecmp(val, "ilp32")) dbg_curr_process->data_model = ilp32_data_model;
  433. else if (!strcasecmp(val, "llp64")) dbg_curr_process->data_model = llp64_data_model;
  434. else if (!strcasecmp(val, "lp64")) dbg_curr_process->data_model = lp64_data_model;
  435. else
  436. dbg_printf("Unknown data model %s\n", val);
  437. }
  438. else dbg_printf("Unknown option '%s'\n", option);
  439. }
  440. BOOL dbg_interrupt_debuggee(void)
  441. {
  442. struct dbg_process* p;
  443. if (list_empty(&dbg_process_list)) return FALSE;
  444. /* FIXME: since we likely have a single process, signal the first process
  445. * in list
  446. */
  447. p = LIST_ENTRY(list_head(&dbg_process_list), struct dbg_process, entry);
  448. if (list_next(&dbg_process_list, &p->entry)) dbg_printf("Ctrl-C: only stopping the first process\n");
  449. else dbg_printf("Ctrl-C: stopping debuggee\n");
  450. if (p->event_on_first_exception)
  451. {
  452. SetEvent(p->event_on_first_exception);
  453. CloseHandle(p->event_on_first_exception);
  454. p->event_on_first_exception = NULL;
  455. }
  456. return DebugBreakProcess(p->handle);
  457. }
  458. static BOOL WINAPI ctrl_c_handler(DWORD dwCtrlType)
  459. {
  460. if (dwCtrlType == CTRL_C_EVENT)
  461. {
  462. return dbg_interrupt_debuggee();
  463. }
  464. return FALSE;
  465. }
  466. void dbg_init_console(void)
  467. {
  468. /* set the output handle */
  469. dbg_houtput = GetStdHandle(STD_OUTPUT_HANDLE);
  470. /* set our control-C handler */
  471. SetConsoleCtrlHandler(ctrl_c_handler, TRUE);
  472. /* set our own title */
  473. SetConsoleTitleA("Wine Debugger");
  474. }
  475. static int dbg_winedbg_usage(BOOL advanced)
  476. {
  477. if (advanced)
  478. {
  479. dbg_printf("Usage:\n"
  480. " winedbg <cmdline> launch process <cmdline> (as if you were starting\n"
  481. " it with wine) and run WineDbg on it\n"
  482. " winedbg <num> attach to running process of wpid <num> and run\n"
  483. " WineDbg on it\n"
  484. " winedbg --gdb <cmdline> launch process <cmdline> (as if you were starting\n"
  485. " wine) and run gdb (proxied) on it\n"
  486. " winedbg --gdb <num> attach to running process of wpid <num> and run\n"
  487. " gdb (proxied) on it\n"
  488. " winedbg <file.mdmp> reload the minidump <file.mdmp> into memory and run\n"
  489. " WineDbg on it\n"
  490. " winedbg --help prints advanced options\n");
  491. }
  492. else
  493. dbg_printf("Usage:\n\twinedbg [ [ --gdb ] [ <prog-name> [ <prog-args> ] | <num> | <file.mdmp> | --help ]\n");
  494. return 0;
  495. }
  496. void dbg_start_interactive(const char* filename, HANDLE hFile)
  497. {
  498. struct dbg_process* p;
  499. struct dbg_process* p2;
  500. if (dbg_curr_process)
  501. {
  502. dbg_printf("WineDbg starting on pid %04lx\n", dbg_curr_pid);
  503. if (dbg_curr_process->active_debuggee) dbg_active_wait_for_first_exception();
  504. }
  505. dbg_interactiveP = TRUE;
  506. parser_handle(filename, hFile);
  507. LIST_FOR_EACH_ENTRY_SAFE(p, p2, &dbg_process_list, struct dbg_process, entry)
  508. p->process_io->close_process(p, FALSE);
  509. dbg_save_internal_vars();
  510. }
  511. static LONG CALLBACK top_filter( EXCEPTION_POINTERS *ptr )
  512. {
  513. dbg_printf( "winedbg: Internal crash at %p\n", ptr->ExceptionRecord->ExceptionAddress );
  514. return EXCEPTION_EXECUTE_HANDLER;
  515. }
  516. static void restart_if_wow64(void)
  517. {
  518. BOOL is_wow64;
  519. if (IsWow64Process( GetCurrentProcess(), &is_wow64 ) && is_wow64)
  520. {
  521. STARTUPINFOW si;
  522. PROCESS_INFORMATION pi;
  523. WCHAR filename[MAX_PATH];
  524. void *redir;
  525. DWORD exit_code;
  526. memset( &si, 0, sizeof(si) );
  527. si.cb = sizeof(si);
  528. GetSystemDirectoryW( filename, MAX_PATH );
  529. lstrcatW( filename, L"\\winedbg.exe" );
  530. Wow64DisableWow64FsRedirection( &redir );
  531. if (CreateProcessW( filename, GetCommandLineW(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ))
  532. {
  533. WINE_TRACE( "restarting %s\n", wine_dbgstr_w(filename) );
  534. SetConsoleCtrlHandler( NULL, TRUE ); /* Ignore ^C */
  535. WaitForSingleObject( pi.hProcess, INFINITE );
  536. GetExitCodeProcess( pi.hProcess, &exit_code );
  537. ExitProcess( exit_code );
  538. }
  539. else WINE_ERR( "failed to restart 64-bit %s, err %ld\n", wine_dbgstr_w(filename), GetLastError() );
  540. Wow64RevertWow64FsRedirection( redir );
  541. }
  542. }
  543. int main(int argc, char** argv)
  544. {
  545. int retv = 0;
  546. HANDLE hFile = INVALID_HANDLE_VALUE;
  547. enum dbg_start ds;
  548. const char* filename = NULL;
  549. /* Initialize the output */
  550. dbg_houtput = GetStdHandle(STD_OUTPUT_HANDLE);
  551. SetUnhandledExceptionFilter( top_filter );
  552. /* Initialize internal vars */
  553. if (!dbg_load_internal_vars()) return -1;
  554. /* as we don't care about exec name */
  555. argc--; argv++;
  556. if (argc && !strcmp(argv[0], "--help"))
  557. return dbg_winedbg_usage(TRUE);
  558. if (argc && !strcmp(argv[0], "--gdb"))
  559. {
  560. restart_if_wow64();
  561. retv = gdb_main(argc, argv);
  562. if (retv == -1) dbg_winedbg_usage(FALSE);
  563. return retv;
  564. }
  565. dbg_init_console();
  566. SymSetOptions((SymGetOptions() & ~(SYMOPT_UNDNAME)) |
  567. SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_AUTO_PUBLICS |
  568. SYMOPT_INCLUDE_32BIT_MODULES);
  569. if (argc && !strcmp(argv[0], "--auto"))
  570. {
  571. switch (dbg_active_auto(argc, argv))
  572. {
  573. case start_ok: return 0;
  574. case start_error_parse: return dbg_winedbg_usage(FALSE);
  575. case start_error_init: return -1;
  576. }
  577. }
  578. if (argc && !strcmp(argv[0], "--minidump"))
  579. {
  580. switch (dbg_active_minidump(argc, argv))
  581. {
  582. case start_ok: return 0;
  583. case start_error_parse: return dbg_winedbg_usage(FALSE);
  584. case start_error_init: return -1;
  585. }
  586. }
  587. /* parse options */
  588. while (argc > 0 && argv[0][0] == '-')
  589. {
  590. if (!strcmp(argv[0], "--command") && argc > 1)
  591. {
  592. argc--; argv++;
  593. hFile = parser_generate_command_file(argv[0], NULL);
  594. if (hFile == INVALID_HANDLE_VALUE)
  595. {
  596. dbg_printf("Couldn't open temp file (%lu)\n", GetLastError());
  597. return 1;
  598. }
  599. argc--; argv++;
  600. continue;
  601. }
  602. if (!strcmp(argv[0], "--file") && argc > 1)
  603. {
  604. argc--; argv++;
  605. filename = argv[0];
  606. hFile = CreateFileA(argv[0], GENERIC_READ|DELETE, 0,
  607. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  608. if (hFile == INVALID_HANDLE_VALUE)
  609. {
  610. dbg_printf("Couldn't open file %s (%lu)\n", argv[0], GetLastError());
  611. return 1;
  612. }
  613. argc--; argv++;
  614. continue;
  615. }
  616. if (!strcmp(argv[0], "--"))
  617. {
  618. argc--; argv++;
  619. break;
  620. }
  621. return dbg_winedbg_usage(FALSE);
  622. }
  623. if (!argc) ds = start_ok;
  624. else if ((ds = dbg_active_attach(argc, argv)) == start_error_parse &&
  625. (ds = minidump_reload(argc, argv)) == start_error_parse)
  626. ds = dbg_active_launch(argc, argv);
  627. switch (ds)
  628. {
  629. case start_ok: break;
  630. case start_error_parse: return dbg_winedbg_usage(FALSE);
  631. case start_error_init: return -1;
  632. }
  633. restart_if_wow64();
  634. dbg_start_interactive(filename, hFile);
  635. return 0;
  636. }