tgt_minidump.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /*
  2. * Wine debugger - minidump handling
  3. *
  4. * Copyright 2005 Eric Pouech
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #define NONAMELESSUNION
  21. #define NONAMELESSSTRUCT
  22. #include "config.h"
  23. #include "wine/port.h"
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <stdarg.h>
  28. #include "debugger.h"
  29. #include "wingdi.h"
  30. #include "winuser.h"
  31. #include "tlhelp32.h"
  32. #include "wine/debug.h"
  33. #include "wine/exception.h"
  34. WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
  35. static struct be_process_io be_process_minidump_io;
  36. /* we need this function on 32bit hosts to ensure we zero out the higher DWORD
  37. * stored in the minidump file (sometimes it's not cleared, or the conversion from
  38. * 32bit to 64bit wide integers is done as signed, which is wrong)
  39. * So we clamp on 32bit CPUs (as stored in minidump information) all addresses to
  40. * keep only the lower 32 bits.
  41. * FIXME: as of today, since we don't support a backend CPU which is different from
  42. * CPU this process is running on, casting to (DWORD_PTR) will do just fine.
  43. */
  44. static inline DWORD64 get_addr64(DWORD64 addr)
  45. {
  46. return (DWORD_PTR)addr;
  47. }
  48. void minidump_write(const char* file, const EXCEPTION_RECORD* rec)
  49. {
  50. HANDLE hFile;
  51. MINIDUMP_EXCEPTION_INFORMATION mei;
  52. EXCEPTION_POINTERS ep;
  53. #ifdef __x86_64__
  54. if (dbg_curr_process->be_cpu->machine != IMAGE_FILE_MACHINE_AMD64)
  55. {
  56. FIXME("Cannot write minidump for 32-bit process using 64-bit winedbg\n");
  57. return;
  58. }
  59. #endif
  60. hFile = CreateFileA(file, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  61. FILE_ATTRIBUTE_NORMAL, NULL);
  62. if (hFile == INVALID_HANDLE_VALUE) return;
  63. if (rec)
  64. {
  65. mei.ThreadId = dbg_curr_thread->tid;
  66. mei.ExceptionPointers = &ep;
  67. ep.ExceptionRecord = (EXCEPTION_RECORD*)rec;
  68. ep.ContextRecord = &dbg_context.ctx;
  69. mei.ClientPointers = FALSE;
  70. }
  71. MiniDumpWriteDump(dbg_curr_process->handle, dbg_curr_process->pid,
  72. hFile, MiniDumpNormal/*|MiniDumpWithDataSegs*/,
  73. rec ? &mei : NULL, NULL, NULL);
  74. CloseHandle(hFile);
  75. }
  76. #define Wine_ElfModuleListStream 0xFFF0
  77. struct tgt_process_minidump_data
  78. {
  79. void* mapping;
  80. HANDLE hFile;
  81. HANDLE hMap;
  82. };
  83. static inline struct tgt_process_minidump_data* private_data(struct dbg_process* pcs)
  84. {
  85. return pcs->pio_data;
  86. }
  87. static BOOL tgt_process_minidump_read(HANDLE hProcess, const void* addr,
  88. void* buffer, SIZE_T len, SIZE_T* rlen)
  89. {
  90. void* stream;
  91. if (!private_data(dbg_curr_process)->mapping) return FALSE;
  92. if (MiniDumpReadDumpStream(private_data(dbg_curr_process)->mapping,
  93. MemoryListStream, NULL, &stream, NULL))
  94. {
  95. MINIDUMP_MEMORY_LIST* mml = stream;
  96. MINIDUMP_MEMORY_DESCRIPTOR* mmd = mml->MemoryRanges;
  97. int i, found = -1;
  98. SIZE_T ilen, prev_len = 0;
  99. /* There's no reason that memory ranges inside a minidump do not overlap.
  100. * So be smart when looking for a given memory range (either grab a
  101. * range that covers the whole requested area, or if none, the range that
  102. * has the largest overlap with requested area)
  103. */
  104. for (i = 0; i < mml->NumberOfMemoryRanges; i++, mmd++)
  105. {
  106. if (get_addr64(mmd->StartOfMemoryRange) <= (DWORD_PTR)addr &&
  107. (DWORD_PTR)addr < get_addr64(mmd->StartOfMemoryRange) + mmd->Memory.DataSize)
  108. {
  109. ilen = min(len,
  110. get_addr64(mmd->StartOfMemoryRange) + mmd->Memory.DataSize - (DWORD_PTR)addr);
  111. if (ilen == len) /* whole range is matched */
  112. {
  113. found = i;
  114. prev_len = ilen;
  115. break;
  116. }
  117. if (found == -1 || ilen > prev_len) /* partial match, keep largest one */
  118. {
  119. found = i;
  120. prev_len = ilen;
  121. }
  122. }
  123. }
  124. if (found != -1)
  125. {
  126. mmd = &mml->MemoryRanges[found];
  127. memcpy(buffer,
  128. (char*)private_data(dbg_curr_process)->mapping + mmd->Memory.Rva + (DWORD_PTR)addr - get_addr64(mmd->StartOfMemoryRange),
  129. prev_len);
  130. if (rlen) *rlen = prev_len;
  131. return TRUE;
  132. }
  133. }
  134. /* FIXME: this is a dirty hack to let the last frame in a bt to work
  135. * However, we need to check who's to blame, this code or the current
  136. * dbghelp!StackWalk implementation
  137. */
  138. if ((DWORD_PTR)addr < 32)
  139. {
  140. memset(buffer, 0, len);
  141. if (rlen) *rlen = len;
  142. return TRUE;
  143. }
  144. return FALSE;
  145. }
  146. static BOOL tgt_process_minidump_write(HANDLE hProcess, void* addr,
  147. const void* buffer, SIZE_T len, SIZE_T* wlen)
  148. {
  149. return FALSE;
  150. }
  151. static BOOL CALLBACK validate_file(PCWSTR name, void* user)
  152. {
  153. return FALSE; /* get the first file we find !! */
  154. }
  155. static BOOL is_pe_module_embedded(struct tgt_process_minidump_data* data,
  156. MINIDUMP_MODULE* pe_mm)
  157. {
  158. MINIDUMP_MODULE_LIST* mml;
  159. if (MiniDumpReadDumpStream(data->mapping, Wine_ElfModuleListStream, NULL,
  160. (void**)&mml, NULL))
  161. {
  162. MINIDUMP_MODULE* mm;
  163. unsigned i;
  164. for (i = 0, mm = mml->Modules; i < mml->NumberOfModules; i++, mm++)
  165. {
  166. if (get_addr64(mm->BaseOfImage) <= get_addr64(pe_mm->BaseOfImage) &&
  167. get_addr64(mm->BaseOfImage) + mm->SizeOfImage >= get_addr64(pe_mm->BaseOfImage) + pe_mm->SizeOfImage)
  168. return TRUE;
  169. }
  170. }
  171. return FALSE;
  172. }
  173. static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data)
  174. {
  175. void* stream;
  176. DWORD pid = 1; /* by default */
  177. HANDLE hProc = (HANDLE)0x900DBAAD;
  178. int i;
  179. MINIDUMP_MODULE_LIST* mml;
  180. MINIDUMP_MODULE* mm;
  181. MINIDUMP_STRING* mds;
  182. MINIDUMP_DIRECTORY* dir;
  183. WCHAR exec_name[1024];
  184. WCHAR nameW[1024];
  185. unsigned len;
  186. static const WCHAR default_exec_name[] = {'<','m','i','n','i','d','u','m','p','-','e','x','e','c','>',0};
  187. /* fetch PID */
  188. if (MiniDumpReadDumpStream(data->mapping, MiscInfoStream, NULL, &stream, NULL))
  189. {
  190. MINIDUMP_MISC_INFO* mmi = stream;
  191. if (mmi->Flags1 & MINIDUMP_MISC1_PROCESS_ID)
  192. pid = mmi->ProcessId;
  193. }
  194. /* fetch executable name (it's normally the first one in module list) */
  195. lstrcpyW(exec_name, default_exec_name);
  196. if (MiniDumpReadDumpStream(data->mapping, ModuleListStream, NULL, &stream, NULL))
  197. {
  198. mml = stream;
  199. if (mml->NumberOfModules)
  200. {
  201. WCHAR* ptr;
  202. mm = mml->Modules;
  203. mds = (MINIDUMP_STRING*)((char*)data->mapping + mm->ModuleNameRva);
  204. len = mds->Length / 2;
  205. memcpy(exec_name, mds->Buffer, mds->Length);
  206. exec_name[len] = 0;
  207. for (ptr = exec_name + len - 1; ptr >= exec_name; ptr--)
  208. {
  209. if (*ptr == '/' || *ptr == '\\')
  210. {
  211. memmove(exec_name, ptr + 1, (lstrlenW(ptr + 1) + 1) * sizeof(WCHAR));
  212. break;
  213. }
  214. }
  215. }
  216. }
  217. if (MiniDumpReadDumpStream(data->mapping, SystemInfoStream, &dir, &stream, NULL))
  218. {
  219. MINIDUMP_SYSTEM_INFO* msi = stream;
  220. const char *str;
  221. char tmp[128];
  222. dbg_printf("WineDbg starting on minidump on pid %04x\n", pid);
  223. switch (msi->ProcessorArchitecture)
  224. {
  225. case PROCESSOR_ARCHITECTURE_UNKNOWN:
  226. str = "Unknown";
  227. break;
  228. case PROCESSOR_ARCHITECTURE_INTEL:
  229. strcpy(tmp, "Intel ");
  230. switch (msi->ProcessorLevel)
  231. {
  232. case 3: str = "80386"; break;
  233. case 4: str = "80486"; break;
  234. case 5: str = "Pentium"; break;
  235. case 6: str = "Pentium Pro/II or AMD Athlon"; break;
  236. case 15: str = "Pentium 4 or AMD Athlon64"; break;
  237. default: str = "???"; break;
  238. }
  239. strcat(tmp, str);
  240. if (msi->ProcessorLevel == 3 || msi->ProcessorLevel == 4)
  241. {
  242. if (HIBYTE(msi->ProcessorRevision) == 0xFF)
  243. sprintf(tmp + strlen(tmp), " (%c%d)",
  244. 'A' + ((msi->ProcessorRevision>>4)&0xf)-0x0a,
  245. ((msi->ProcessorRevision&0xf)));
  246. else
  247. sprintf(tmp + strlen(tmp), " (%c%d)",
  248. 'A' + HIBYTE(msi->ProcessorRevision),
  249. LOBYTE(msi->ProcessorRevision));
  250. }
  251. else sprintf(tmp + strlen(tmp), " (%d.%d)",
  252. HIBYTE(msi->ProcessorRevision),
  253. LOBYTE(msi->ProcessorRevision));
  254. str = tmp;
  255. break;
  256. case PROCESSOR_ARCHITECTURE_MIPS:
  257. str = "Mips";
  258. break;
  259. case PROCESSOR_ARCHITECTURE_ALPHA:
  260. str = "Alpha";
  261. break;
  262. case PROCESSOR_ARCHITECTURE_PPC:
  263. str = "PowerPC";
  264. break;
  265. case PROCESSOR_ARCHITECTURE_AMD64:
  266. str = "X86_64";
  267. break;
  268. case PROCESSOR_ARCHITECTURE_ARM:
  269. str = "ARM";
  270. break;
  271. case PROCESSOR_ARCHITECTURE_ARM64:
  272. str = "ARM64";
  273. break;
  274. case PROCESSOR_ARCHITECTURE_MSIL:
  275. str = "MSIL";
  276. break;
  277. case PROCESSOR_ARCHITECTURE_NEUTRAL:
  278. str = "Neutral";
  279. break;
  280. default:
  281. str = "???";
  282. break;
  283. }
  284. dbg_printf(" %s was running on #%d %s CPU%s",
  285. dbg_W2A(exec_name, -1), msi->u.s.NumberOfProcessors, str,
  286. msi->u.s.NumberOfProcessors < 2 ? "" : "s");
  287. switch (msi->MajorVersion)
  288. {
  289. case 3:
  290. switch (msi->MinorVersion)
  291. {
  292. case 51: str = "NT 3.51"; break;
  293. default: str = "3-????"; break;
  294. }
  295. break;
  296. case 4:
  297. switch (msi->MinorVersion)
  298. {
  299. case 0: str = (msi->PlatformId == VER_PLATFORM_WIN32_NT) ? "NT 4.0" : "95"; break;
  300. case 10: str = "98"; break;
  301. case 90: str = "ME"; break;
  302. default: str = "4-????"; break;
  303. }
  304. break;
  305. case 5:
  306. switch (msi->MinorVersion)
  307. {
  308. case 0: str = "2000"; break;
  309. case 1: str = "XP"; break;
  310. case 2:
  311. if (msi->u.s.ProductType == 1) str = "XP";
  312. else if (msi->u.s.ProductType == 3) str = "Server 2003";
  313. else str = "5-????";
  314. break;
  315. default: str = "5-????"; break;
  316. }
  317. break;
  318. case 6:
  319. switch (msi->MinorVersion)
  320. {
  321. case 0:
  322. if (msi->u.s.ProductType == 1) str = "Vista";
  323. else if (msi->u.s.ProductType == 3) str = "Server 2008";
  324. else str = "6-????";
  325. break;
  326. case 1:
  327. if (msi->u.s.ProductType == 1) str = "Win7";
  328. else if (msi->u.s.ProductType == 3) str = "Server 2008";
  329. else str = "6-????";
  330. break;
  331. case 2:
  332. if (msi->u.s.ProductType == 1) str = "Win8";
  333. else if (msi->u.s.ProductType == 3) str = "Server 2012";
  334. else str = "6-????";
  335. break;
  336. case 3:
  337. if (msi->u.s.ProductType == 1) str = "Win8.1";
  338. else if (msi->u.s.ProductType == 3) str = "Server 2012 R2";
  339. else str = "6-????";
  340. break;
  341. default: str = "6-????"; break;
  342. }
  343. break;
  344. case 10:
  345. switch (msi->MinorVersion)
  346. {
  347. case 0:
  348. if (msi->u.s.ProductType == 1) str = "Win10";
  349. else str = "10-????";
  350. break;
  351. default: str = "10-????"; break;
  352. }
  353. break;
  354. default: str = "???"; break;
  355. }
  356. dbg_printf(" on Windows %s (%u)\n", str, msi->BuildNumber);
  357. /* FIXME CSD: msi->CSDVersionRva */
  358. if (sizeof(MINIDUMP_SYSTEM_INFO) + 4 > dir->Location.DataSize &&
  359. msi->CSDVersionRva >= dir->Location.Rva + sizeof(MINIDUMP_SYSTEM_INFO) + 4)
  360. {
  361. const char* code = (const char*)stream + sizeof(MINIDUMP_SYSTEM_INFO);
  362. const DWORD* wes;
  363. if (code[0] == 'W' && code[1] == 'I' && code[2] == 'N' && code[3] == 'E' &&
  364. *(wes = (const DWORD*)(code += 4)) >= 3)
  365. {
  366. /* assume we have wine extensions */
  367. dbg_printf(" [on %s, on top of %s (%s)]\n",
  368. code + wes[1], code + wes[2], code + wes[3]);
  369. }
  370. }
  371. }
  372. dbg_curr_process = dbg_add_process(&be_process_minidump_io, pid, hProc);
  373. dbg_curr_pid = pid;
  374. dbg_curr_process->pio_data = data;
  375. dbg_set_process_name(dbg_curr_process, exec_name);
  376. dbg_init(hProc, NULL, FALSE);
  377. if (MiniDumpReadDumpStream(data->mapping, ThreadListStream, NULL, &stream, NULL))
  378. {
  379. MINIDUMP_THREAD_LIST* mtl = stream;
  380. ULONG i;
  381. for (i = 0; i < mtl->NumberOfThreads; i++)
  382. {
  383. dbg_add_thread(dbg_curr_process, mtl->Threads[i].ThreadId, NULL,
  384. (void*)(DWORD_PTR)get_addr64(mtl->Threads[i].Teb));
  385. }
  386. }
  387. /* first load ELF modules, then do the PE ones */
  388. if (MiniDumpReadDumpStream(data->mapping, Wine_ElfModuleListStream, NULL,
  389. &stream, NULL))
  390. {
  391. WCHAR buffer[MAX_PATH];
  392. mml = stream;
  393. for (i = 0, mm = mml->Modules; i < mml->NumberOfModules; i++, mm++)
  394. {
  395. mds = (MINIDUMP_STRING*)((char*)data->mapping + mm->ModuleNameRva);
  396. memcpy(nameW, mds->Buffer, mds->Length);
  397. nameW[mds->Length / sizeof(WCHAR)] = 0;
  398. if (SymFindFileInPathW(hProc, NULL, nameW, (void*)(DWORD_PTR)mm->CheckSum,
  399. 0, 0, SSRVOPT_DWORD, buffer, validate_file, NULL))
  400. dbg_load_module(hProc, NULL, buffer, get_addr64(mm->BaseOfImage),
  401. mm->SizeOfImage);
  402. else
  403. SymLoadModuleExW(hProc, NULL, nameW, NULL, get_addr64(mm->BaseOfImage),
  404. mm->SizeOfImage, NULL, SLMFLAG_VIRTUAL);
  405. }
  406. }
  407. if (MiniDumpReadDumpStream(data->mapping, ModuleListStream, NULL, &stream, NULL))
  408. {
  409. WCHAR buffer[MAX_PATH];
  410. mml = stream;
  411. for (i = 0, mm = mml->Modules; i < mml->NumberOfModules; i++, mm++)
  412. {
  413. mds = (MINIDUMP_STRING*)((char*)data->mapping + mm->ModuleNameRva);
  414. memcpy(nameW, mds->Buffer, mds->Length);
  415. nameW[mds->Length / sizeof(WCHAR)] = 0;
  416. if (SymFindFileInPathW(hProc, NULL, nameW, (void*)(DWORD_PTR)mm->TimeDateStamp,
  417. mm->SizeOfImage, 0, SSRVOPT_DWORD, buffer, validate_file, NULL))
  418. dbg_load_module(hProc, NULL, buffer, get_addr64(mm->BaseOfImage),
  419. mm->SizeOfImage);
  420. else if (is_pe_module_embedded(data, mm))
  421. dbg_load_module(hProc, NULL, nameW, get_addr64(mm->BaseOfImage),
  422. mm->SizeOfImage);
  423. else
  424. SymLoadModuleExW(hProc, NULL, nameW, NULL, get_addr64(mm->BaseOfImage),
  425. mm->SizeOfImage, NULL, SLMFLAG_VIRTUAL);
  426. }
  427. }
  428. if (MiniDumpReadDumpStream(data->mapping, ExceptionStream, NULL, &stream, NULL))
  429. {
  430. MINIDUMP_EXCEPTION_STREAM* mes = stream;
  431. if ((dbg_curr_thread = dbg_get_thread(dbg_curr_process, mes->ThreadId)))
  432. {
  433. ADDRESS64 addr;
  434. dbg_curr_tid = mes->ThreadId;
  435. dbg_curr_thread->in_exception = TRUE;
  436. dbg_curr_thread->excpt_record.ExceptionCode = mes->ExceptionRecord.ExceptionCode;
  437. dbg_curr_thread->excpt_record.ExceptionFlags = mes->ExceptionRecord.ExceptionFlags;
  438. dbg_curr_thread->excpt_record.ExceptionRecord = (void*)(DWORD_PTR)get_addr64(mes->ExceptionRecord.ExceptionRecord);
  439. dbg_curr_thread->excpt_record.ExceptionAddress = (void*)(DWORD_PTR)get_addr64(mes->ExceptionRecord.ExceptionAddress);
  440. dbg_curr_thread->excpt_record.NumberParameters = mes->ExceptionRecord.NumberParameters;
  441. for (i = 0; i < dbg_curr_thread->excpt_record.NumberParameters; i++)
  442. {
  443. dbg_curr_thread->excpt_record.ExceptionInformation[i] = mes->ExceptionRecord.ExceptionInformation[i];
  444. }
  445. memcpy(&dbg_context, (char*)data->mapping + mes->ThreadContext.Rva,
  446. min(sizeof(dbg_context), mes->ThreadContext.DataSize));
  447. memory_get_current_pc(&addr);
  448. stack_fetch_frames(&dbg_context);
  449. dbg_curr_process->be_cpu->print_context(dbg_curr_thread->handle, &dbg_context, 0);
  450. stack_info(-1);
  451. dbg_curr_process->be_cpu->print_segment_info(dbg_curr_thread->handle, &dbg_context);
  452. stack_backtrace(mes->ThreadId);
  453. source_list_from_addr(&addr, 0);
  454. }
  455. }
  456. return start_ok;
  457. }
  458. static void cleanup(struct tgt_process_minidump_data* data)
  459. {
  460. if (data->mapping) UnmapViewOfFile(data->mapping);
  461. if (data->hMap) CloseHandle(data->hMap);
  462. if (data->hFile != INVALID_HANDLE_VALUE) CloseHandle(data->hFile);
  463. HeapFree(GetProcessHeap(), 0, data);
  464. }
  465. static struct be_process_io be_process_minidump_io;
  466. enum dbg_start minidump_reload(int argc, char* argv[])
  467. {
  468. struct tgt_process_minidump_data* data;
  469. enum dbg_start ret = start_error_parse;
  470. /* try the form <myself> minidump-file */
  471. if (argc != 1) return start_error_parse;
  472. WINE_TRACE("Processing Minidump file %s\n", argv[0]);
  473. data = HeapAlloc(GetProcessHeap(), 0, sizeof(struct tgt_process_minidump_data));
  474. if (!data) return start_error_init;
  475. data->mapping = NULL;
  476. data->hMap = NULL;
  477. data->hFile = INVALID_HANDLE_VALUE;
  478. if ((data->hFile = CreateFileA(argv[0], GENERIC_READ, FILE_SHARE_READ, NULL,
  479. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE &&
  480. ((data->hMap = CreateFileMappingA(data->hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) &&
  481. ((data->mapping = MapViewOfFile(data->hMap, FILE_MAP_READ, 0, 0, 0)) != NULL))
  482. {
  483. __TRY
  484. {
  485. if (((MINIDUMP_HEADER*)data->mapping)->Signature == MINIDUMP_SIGNATURE)
  486. {
  487. ret = minidump_do_reload(data);
  488. }
  489. }
  490. __EXCEPT_PAGE_FAULT
  491. {
  492. dbg_printf("Unexpected fault while reading minidump %s\n", argv[0]);
  493. dbg_curr_pid = 0;
  494. }
  495. __ENDTRY;
  496. }
  497. if (ret != start_ok) cleanup(data);
  498. return ret;
  499. }
  500. static BOOL tgt_process_minidump_close_process(struct dbg_process* pcs, BOOL kill)
  501. {
  502. struct tgt_process_minidump_data* data = private_data(pcs);
  503. cleanup(data);
  504. pcs->pio_data = NULL;
  505. SymCleanup(pcs->handle);
  506. dbg_del_process(pcs);
  507. return TRUE;
  508. }
  509. static BOOL tgt_process_minidump_get_selector(HANDLE hThread, DWORD sel, LDT_ENTRY* le)
  510. {
  511. /* so far, pretend all selectors are valid, and mapped to a 32bit flat address space */
  512. memset(le, 0, sizeof(*le));
  513. le->HighWord.Bits.Default_Big = 1;
  514. return TRUE;
  515. }
  516. static struct be_process_io be_process_minidump_io =
  517. {
  518. tgt_process_minidump_close_process,
  519. tgt_process_minidump_read,
  520. tgt_process_minidump_write,
  521. tgt_process_minidump_get_selector,
  522. };