tgt_minidump.c 20 KB

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