atl80: Added AtlComModuleRegisterServer implementation (based on AtlModuleRegisterSer...
[wine] / dlls / dbghelp / minidump.c
1 /*
2  * File minidump.c - management of dumps (read & write)
3  *
4  * Copyright (C) 2004-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
21 #include <time.h>
22
23 #define NONAMELESSUNION
24 #define NONAMELESSSTRUCT
25
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "dbghelp_private.h"
29 #include "winternl.h"
30 #include "psapi.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
34
35 /******************************************************************
36  *              fetch_process_info
37  *
38  * reads system wide process information, and gather from it the threads information
39  * for process of id 'pid'
40  */
41 static BOOL fetch_process_info(struct dump_context* dc)
42 {
43     ULONG       buf_size = 0x1000;
44     NTSTATUS    nts;
45     void*       pcs_buffer = NULL;
46
47     if (!(pcs_buffer = HeapAlloc(GetProcessHeap(), 0, buf_size))) return FALSE;
48     for (;;)
49     {
50         nts = NtQuerySystemInformation(SystemProcessInformation,
51                                        pcs_buffer, buf_size, NULL);
52         if (nts != STATUS_INFO_LENGTH_MISMATCH) break;
53         pcs_buffer = HeapReAlloc(GetProcessHeap(), 0, pcs_buffer, buf_size *= 2);
54         if (!pcs_buffer) return FALSE;
55     }
56
57     if (nts == STATUS_SUCCESS)
58     {
59         SYSTEM_PROCESS_INFORMATION*     spi = pcs_buffer;
60         unsigned                        i;
61
62         for (;;)
63         {
64             if (HandleToUlong(spi->UniqueProcessId) == dc->pid)
65             {
66                 dc->num_threads = spi->dwThreadCount;
67                 dc->threads = HeapAlloc(GetProcessHeap(), 0,
68                                         dc->num_threads * sizeof(dc->threads[0]));
69                 if (!dc->threads) goto failed;
70                 for (i = 0; i < dc->num_threads; i++)
71                 {
72                     dc->threads[i].tid        = HandleToULong(spi->ti[i].ClientId.UniqueThread);
73                     dc->threads[i].prio_class = spi->ti[i].dwBasePriority; /* FIXME */
74                     dc->threads[i].curr_prio  = spi->ti[i].dwCurrentPriority;
75                 }
76                 HeapFree(GetProcessHeap(), 0, pcs_buffer);
77                 return TRUE;
78             }
79             if (!spi->NextEntryOffset) break;
80             spi = (SYSTEM_PROCESS_INFORMATION*)((char*)spi + spi->NextEntryOffset);
81         }
82     }
83 failed:
84     HeapFree(GetProcessHeap(), 0, pcs_buffer);
85     return FALSE;
86 }
87
88 static void fetch_thread_stack(struct dump_context* dc, const void* teb_addr,
89                                const CONTEXT* ctx, MINIDUMP_MEMORY_DESCRIPTOR* mmd)
90 {
91     NT_TIB      tib;
92     ADDRESS64   addr;
93
94     if (ReadProcessMemory(dc->hProcess, teb_addr, &tib, sizeof(tib), NULL) &&
95         dbghelp_current_cpu &&
96         dbghelp_current_cpu->get_addr(NULL /* FIXME */, ctx, cpu_addr_stack, &addr) && addr.Mode == AddrModeFlat)
97     {
98         if (addr.Offset)
99         {
100             addr.Offset -= dbghelp_current_cpu->word_size;
101             /* make sure stack pointer is within the established range of the stack.  It could have
102                been clobbered by whatever caused the original exception. */
103             if (addr.Offset < (ULONG_PTR)tib.StackLimit || addr.Offset > (ULONG_PTR)tib.StackBase)
104                 mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
105
106             else
107                 mmd->StartOfMemoryRange = addr.Offset;
108         }
109         else
110             mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
111         mmd->Memory.DataSize = (ULONG_PTR)tib.StackBase - mmd->StartOfMemoryRange;
112     }
113 }
114
115 /******************************************************************
116  *              fetch_thread_info
117  *
118  * fetches some information about thread of id 'tid'
119  */
120 static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx,
121                               const MINIDUMP_EXCEPTION_INFORMATION* except,
122                               MINIDUMP_THREAD* mdThd, CONTEXT* ctx)
123 {
124     DWORD                       tid = dc->threads[thd_idx].tid;
125     HANDLE                      hThread;
126     THREAD_BASIC_INFORMATION    tbi;
127
128     memset(ctx, 0, sizeof(*ctx));
129
130     mdThd->ThreadId = tid;
131     mdThd->SuspendCount = 0;
132     mdThd->Teb = 0;
133     mdThd->Stack.StartOfMemoryRange = 0;
134     mdThd->Stack.Memory.DataSize = 0;
135     mdThd->Stack.Memory.Rva = 0;
136     mdThd->ThreadContext.DataSize = 0;
137     mdThd->ThreadContext.Rva = 0;
138     mdThd->PriorityClass = dc->threads[thd_idx].prio_class;
139     mdThd->Priority = dc->threads[thd_idx].curr_prio;
140
141     if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL)
142     {
143         FIXME("Couldn't open thread %u (%u)\n", tid, GetLastError());
144         return FALSE;
145     }
146     
147     if (NtQueryInformationThread(hThread, ThreadBasicInformation,
148                                  &tbi, sizeof(tbi), NULL) == STATUS_SUCCESS)
149     {
150         mdThd->Teb = (ULONG_PTR)tbi.TebBaseAddress;
151         if (tbi.ExitStatus == STILL_ACTIVE)
152         {
153             if (tid != GetCurrentThreadId() &&
154                 (mdThd->SuspendCount = SuspendThread(hThread)) != (DWORD)-1)
155             {
156                 ctx->ContextFlags = CONTEXT_FULL;
157                 if (!GetThreadContext(hThread, ctx))
158                     memset(ctx, 0, sizeof(*ctx));
159
160                 fetch_thread_stack(dc, tbi.TebBaseAddress, ctx, &mdThd->Stack);
161                 ResumeThread(hThread);
162             }
163             else if (tid == GetCurrentThreadId() && except)
164             {
165                 CONTEXT lctx, *pctx;
166                 mdThd->SuspendCount = 1;
167                 if (except->ClientPointers)
168                 {
169                     EXCEPTION_POINTERS      ep;
170
171                     ReadProcessMemory(dc->hProcess, except->ExceptionPointers,
172                                       &ep, sizeof(ep), NULL);
173                     ReadProcessMemory(dc->hProcess, ep.ContextRecord,
174                                       &lctx, sizeof(lctx), NULL);
175                     pctx = &lctx;
176                 }
177                 else pctx = except->ExceptionPointers->ContextRecord;
178
179                 *ctx = *pctx;
180                 fetch_thread_stack(dc, tbi.TebBaseAddress, pctx, &mdThd->Stack);
181             }
182             else mdThd->SuspendCount = 0;
183         }
184     }
185     CloseHandle(hThread);
186     return TRUE;
187 }
188
189 /******************************************************************
190  *              add_module
191  *
192  * Add a module to a dump context
193  */
194 static BOOL add_module(struct dump_context* dc, const WCHAR* name,
195                        DWORD64 base, DWORD size, DWORD timestamp, DWORD checksum,
196                        BOOL is_elf)
197 {
198     if (!dc->modules)
199     {
200         dc->alloc_modules = 32;
201         dc->modules = HeapAlloc(GetProcessHeap(), 0,
202                                 dc->alloc_modules * sizeof(*dc->modules));
203     }
204     else if(dc->num_modules >= dc->alloc_modules)
205     {
206         dc->alloc_modules *= 2;
207         dc->modules = HeapReAlloc(GetProcessHeap(), 0, dc->modules,
208                                   dc->alloc_modules * sizeof(*dc->modules));
209     }
210     if (!dc->modules)
211     {
212         dc->alloc_modules = dc->num_modules = 0;
213         return FALSE;
214     }
215     if (is_elf ||
216         !GetModuleFileNameExW(dc->hProcess, (HMODULE)(DWORD_PTR)base,
217                               dc->modules[dc->num_modules].name,
218                               sizeof(dc->modules[dc->num_modules].name) / sizeof(WCHAR)))
219         lstrcpynW(dc->modules[dc->num_modules].name, name,
220                   sizeof(dc->modules[dc->num_modules].name) / sizeof(WCHAR));
221     dc->modules[dc->num_modules].base = base;
222     dc->modules[dc->num_modules].size = size;
223     dc->modules[dc->num_modules].timestamp = timestamp;
224     dc->modules[dc->num_modules].checksum = checksum;
225     dc->modules[dc->num_modules].is_elf = is_elf;
226     dc->num_modules++;
227
228     return TRUE;
229 }
230
231 /******************************************************************
232  *              fetch_pe_module_info_cb
233  *
234  * Callback for accumulating in dump_context a PE modules set
235  */
236 static BOOL WINAPI fetch_pe_module_info_cb(PCWSTR name, DWORD64 base, ULONG size,
237                                            PVOID user)
238 {
239     struct dump_context*        dc = user;
240     IMAGE_NT_HEADERS            nth;
241
242     if (!validate_addr64(base)) return FALSE;
243
244     if (pe_load_nt_header(dc->hProcess, base, &nth))
245         add_module(user, name, base, size,
246                    nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum,
247                    FALSE);
248     return TRUE;
249 }
250
251 /******************************************************************
252  *              fetch_elf_module_info_cb
253  *
254  * Callback for accumulating in dump_context an ELF modules set
255  */
256 static BOOL fetch_elf_module_info_cb(const WCHAR* name, unsigned long base,
257                                      void* user)
258 {
259     struct dump_context*        dc = user;
260     DWORD_PTR                   rbase;
261     DWORD                       size, checksum;
262
263     /* FIXME: there's no relevant timestamp on ELF modules */
264     /* NB: if we have a non-null base from the live-target use it (whenever
265      * the ELF module is relocatable or not). If we have a null base (ELF
266      * module isn't relocatable) then grab its base address from ELF file
267      */
268     if (!elf_fetch_file_info(name, &rbase, &size, &checksum))
269         size = checksum = 0;
270     add_module(dc, name, base ? base : rbase, size, 0 /* FIXME */, checksum, TRUE);
271     return TRUE;
272 }
273
274 /******************************************************************
275  *              fetch_macho_module_info_cb
276  *
277  * Callback for accumulating in dump_context a Mach-O modules set
278  */
279 static BOOL fetch_macho_module_info_cb(const WCHAR* name, unsigned long base,
280                                        void* user)
281 {
282     struct dump_context*        dc = (struct dump_context*)user;
283     DWORD_PTR                   rbase;
284     DWORD                       size, checksum;
285
286     /* FIXME: there's no relevant timestamp on Mach-O modules */
287     /* NB: if we have a non-null base from the live-target use it.  If we have
288      * a null base, then grab its base address from Mach-O file.
289      */
290     if (!macho_fetch_file_info(name, &rbase, &size, &checksum))
291         size = checksum = 0;
292     add_module(dc, name, base ? base : rbase, size, 0 /* FIXME */, checksum, TRUE);
293     return TRUE;
294 }
295
296 static void fetch_modules_info(struct dump_context* dc)
297 {
298     EnumerateLoadedModulesW64(dc->hProcess, fetch_pe_module_info_cb, dc);
299     /* Since we include ELF modules in a separate stream from the regular PE ones,
300      * we can always include those ELF modules (they don't eat lots of space)
301      * And it's always a good idea to have a trace of the loaded ELF modules for
302      * a given application in a post mortem debugging condition.
303      */
304     elf_enum_modules(dc->hProcess, fetch_elf_module_info_cb, dc);
305     macho_enum_modules(dc->hProcess, fetch_macho_module_info_cb, dc);
306 }
307
308 static void fetch_module_versioninfo(LPCWSTR filename, VS_FIXEDFILEINFO* ffi)
309 {
310     DWORD       handle;
311     DWORD       sz;
312     static const WCHAR backslashW[] = {'\\', '\0'};
313
314     memset(ffi, 0, sizeof(*ffi));
315     if ((sz = GetFileVersionInfoSizeW(filename, &handle)))
316     {
317         void*   info = HeapAlloc(GetProcessHeap(), 0, sz);
318         if (info && GetFileVersionInfoW(filename, handle, sz, info))
319         {
320             VS_FIXEDFILEINFO*   ptr;
321             UINT    len;
322
323             if (VerQueryValueW(info, backslashW, (void*)&ptr, &len))
324                 memcpy(ffi, ptr, min(len, sizeof(*ffi)));
325         }
326         HeapFree(GetProcessHeap(), 0, info);
327     }
328 }
329
330 /******************************************************************
331  *              minidump_add_memory_block
332  *
333  * Add a memory block to be dumped in a minidump
334  * If rva is non 0, it's the rva in the minidump where has to be stored
335  * also the rva of the memory block when written (this allows us to reference
336  * a memory block from outside the list of memory blocks).
337  */
338 void minidump_add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva)
339 {
340     if (!dc->mem)
341     {
342         dc->alloc_mem = 32;
343         dc->mem = HeapAlloc(GetProcessHeap(), 0, dc->alloc_mem * sizeof(*dc->mem));
344     }
345     else if (dc->num_mem >= dc->alloc_mem)
346     {
347         dc->alloc_mem *= 2;
348         dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem,
349                               dc->alloc_mem * sizeof(*dc->mem));
350     }
351     if (dc->mem)
352     {
353         dc->mem[dc->num_mem].base = base;
354         dc->mem[dc->num_mem].size = size;
355         dc->mem[dc->num_mem].rva  = rva;
356         dc->num_mem++;
357     }
358     else dc->num_mem = dc->alloc_mem = 0;
359 }
360
361 /******************************************************************
362  *              writeat
363  *
364  * Writes a chunk of data at a given position in the minidump
365  */
366 static void writeat(struct dump_context* dc, RVA rva, const void* data, unsigned size)
367 {
368     DWORD       written;
369
370     SetFilePointer(dc->hFile, rva, NULL, FILE_BEGIN);
371     WriteFile(dc->hFile, data, size, &written, NULL);
372 }
373
374 /******************************************************************
375  *              append
376  *
377  * writes a new chunk of data to the minidump, increasing the current
378  * rva in dc
379  */
380 static void append(struct dump_context* dc, const void* data, unsigned size)
381 {
382     writeat(dc, dc->rva, data, size);
383     dc->rva += size;
384 }
385
386 /******************************************************************
387  *              dump_exception_info
388  *
389  * Write in File the exception information from pcs
390  */
391 static  unsigned        dump_exception_info(struct dump_context* dc,
392                                             const MINIDUMP_EXCEPTION_INFORMATION* except)
393 {
394     MINIDUMP_EXCEPTION_STREAM   mdExcpt;
395     EXCEPTION_RECORD            rec, *prec;
396     CONTEXT                     ctx, *pctx;
397     DWORD                       i;
398
399     mdExcpt.ThreadId = except->ThreadId;
400     mdExcpt.__alignment = 0;
401     if (except->ClientPointers)
402     {
403         EXCEPTION_POINTERS      ep;
404
405         ReadProcessMemory(dc->hProcess, 
406                           except->ExceptionPointers, &ep, sizeof(ep), NULL);
407         ReadProcessMemory(dc->hProcess, 
408                           ep.ExceptionRecord, &rec, sizeof(rec), NULL);
409         ReadProcessMemory(dc->hProcess, 
410                           ep.ContextRecord, &ctx, sizeof(ctx), NULL);
411         prec = &rec;
412         pctx = &ctx;
413     }
414     else
415     {
416         prec = except->ExceptionPointers->ExceptionRecord;
417         pctx = except->ExceptionPointers->ContextRecord;
418     }
419     mdExcpt.ExceptionRecord.ExceptionCode = prec->ExceptionCode;
420     mdExcpt.ExceptionRecord.ExceptionFlags = prec->ExceptionFlags;
421     mdExcpt.ExceptionRecord.ExceptionRecord = (DWORD_PTR)prec->ExceptionRecord;
422     mdExcpt.ExceptionRecord.ExceptionAddress = (DWORD_PTR)prec->ExceptionAddress;
423     mdExcpt.ExceptionRecord.NumberParameters = prec->NumberParameters;
424     mdExcpt.ExceptionRecord.__unusedAlignment = 0;
425     for (i = 0; i < mdExcpt.ExceptionRecord.NumberParameters; i++)
426         mdExcpt.ExceptionRecord.ExceptionInformation[i] = prec->ExceptionInformation[i];
427     mdExcpt.ThreadContext.DataSize = sizeof(*pctx);
428     mdExcpt.ThreadContext.Rva = dc->rva + sizeof(mdExcpt);
429
430     append(dc, &mdExcpt, sizeof(mdExcpt));
431     append(dc, pctx, sizeof(*pctx));
432     return sizeof(mdExcpt);
433 }
434
435 /******************************************************************
436  *              dump_modules
437  *
438  * Write in File the modules from pcs
439  */
440 static  unsigned        dump_modules(struct dump_context* dc, BOOL dump_elf)
441 {
442     MINIDUMP_MODULE             mdModule;
443     MINIDUMP_MODULE_LIST        mdModuleList;
444     char                        tmp[1024];
445     MINIDUMP_STRING*            ms = (MINIDUMP_STRING*)tmp;
446     ULONG                       i, nmod;
447     RVA                         rva_base;
448     DWORD                       flags_out;
449     unsigned                    sz;
450
451     for (i = nmod = 0; i < dc->num_modules; i++)
452     {
453         if ((dc->modules[i].is_elf && dump_elf) ||
454             (!dc->modules[i].is_elf && !dump_elf))
455             nmod++;
456     }
457
458     mdModuleList.NumberOfModules = 0;
459     /* reserve space for mdModuleList
460      * FIXME: since we don't support 0 length arrays, we cannot use the
461      * size of mdModuleList
462      * FIXME: if we don't ask for all modules in cb, we'll get a hole in the file
463      */
464
465     /* the stream size is just the size of the module index.  It does not include the data for the
466        names of each module.  *Technically* the names are supposed to go into the common string table
467        in the minidump file.  Since each string is referenced by RVA they can all safely be located
468        anywhere between streams in the file, so the end of this stream is sufficient. */
469     rva_base = dc->rva;
470     dc->rva += sz = sizeof(mdModuleList.NumberOfModules) + sizeof(mdModule) * nmod;
471     for (i = 0; i < dc->num_modules; i++)
472     {
473         if ((dc->modules[i].is_elf && !dump_elf) ||
474             (!dc->modules[i].is_elf && dump_elf))
475             continue;
476
477         flags_out = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteCvRecord;
478         if (dc->type & MiniDumpWithDataSegs)
479             flags_out |= ModuleWriteDataSeg;
480         if (dc->type & MiniDumpWithProcessThreadData)
481             flags_out |= ModuleWriteTlsData;
482         if (dc->type & MiniDumpWithCodeSegs)
483             flags_out |= ModuleWriteCodeSegs;
484         ms->Length = (lstrlenW(dc->modules[i].name) + 1) * sizeof(WCHAR);
485         if (sizeof(ULONG) + ms->Length > sizeof(tmp))
486             FIXME("Buffer overflow!!!\n");
487         lstrcpyW(ms->Buffer, dc->modules[i].name);
488
489         if (dc->cb)
490         {
491             MINIDUMP_CALLBACK_INPUT     cbin;
492             MINIDUMP_CALLBACK_OUTPUT    cbout;
493
494             cbin.ProcessId = dc->pid;
495             cbin.ProcessHandle = dc->hProcess;
496             cbin.CallbackType = ModuleCallback;
497
498             cbin.u.Module.FullPath = ms->Buffer;
499             cbin.u.Module.BaseOfImage = dc->modules[i].base;
500             cbin.u.Module.SizeOfImage = dc->modules[i].size;
501             cbin.u.Module.CheckSum = dc->modules[i].checksum;
502             cbin.u.Module.TimeDateStamp = dc->modules[i].timestamp;
503             memset(&cbin.u.Module.VersionInfo, 0, sizeof(cbin.u.Module.VersionInfo));
504             cbin.u.Module.CvRecord = NULL;
505             cbin.u.Module.SizeOfCvRecord = 0;
506             cbin.u.Module.MiscRecord = NULL;
507             cbin.u.Module.SizeOfMiscRecord = 0;
508
509             cbout.u.ModuleWriteFlags = flags_out;
510             if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
511                 continue;
512             flags_out &= cbout.u.ModuleWriteFlags;
513         }
514         if (flags_out & ModuleWriteModule)
515         {
516             /* fetch CPU dependent module info (like UNWIND_INFO) */
517             dbghelp_current_cpu->fetch_minidump_module(dc, i, flags_out);
518
519             mdModule.BaseOfImage = dc->modules[i].base;
520             mdModule.SizeOfImage = dc->modules[i].size;
521             mdModule.CheckSum = dc->modules[i].checksum;
522             mdModule.TimeDateStamp = dc->modules[i].timestamp;
523             mdModule.ModuleNameRva = dc->rva;
524             ms->Length -= sizeof(WCHAR);
525             append(dc, ms, sizeof(ULONG) + ms->Length + sizeof(WCHAR));
526             fetch_module_versioninfo(ms->Buffer, &mdModule.VersionInfo);
527             mdModule.CvRecord.DataSize = 0; /* FIXME */
528             mdModule.CvRecord.Rva = 0; /* FIXME */
529             mdModule.MiscRecord.DataSize = 0; /* FIXME */
530             mdModule.MiscRecord.Rva = 0; /* FIXME */
531             mdModule.Reserved0 = 0; /* FIXME */
532             mdModule.Reserved1 = 0; /* FIXME */
533             writeat(dc,
534                     rva_base + sizeof(mdModuleList.NumberOfModules) + 
535                         mdModuleList.NumberOfModules++ * sizeof(mdModule), 
536                     &mdModule, sizeof(mdModule));
537         }
538     }
539     writeat(dc, rva_base, &mdModuleList.NumberOfModules, 
540             sizeof(mdModuleList.NumberOfModules));
541
542     return sz;
543 }
544
545 /* Calls cpuid with an eax of 'ax' and returns the 16 bytes in *p
546  * We are compiled with -fPIC, so we can't clobber ebx.
547  */
548 static inline void do_x86cpuid(unsigned int ax, unsigned int *p)
549 {
550 #if defined(__GNUC__) && defined(__i386__)
551     __asm__("pushl %%ebx\n\t"
552             "cpuid\n\t"
553             "movl %%ebx, %%esi\n\t"
554             "popl %%ebx"
555             : "=a" (p[0]), "=S" (p[1]), "=c" (p[2]), "=d" (p[3])
556             :  "0" (ax));
557 #endif
558 }
559
560 /* From xf86info havecpuid.c 1.11 */
561 static inline int have_x86cpuid(void)
562 {
563 #if defined(__GNUC__) && defined(__i386__)
564     unsigned int f1, f2;
565     __asm__("pushfl\n\t"
566             "pushfl\n\t"
567             "popl %0\n\t"
568             "movl %0,%1\n\t"
569             "xorl %2,%0\n\t"
570             "pushl %0\n\t"
571             "popfl\n\t"
572             "pushfl\n\t"
573             "popl %0\n\t"
574             "popfl"
575             : "=&r" (f1), "=&r" (f2)
576             : "ir" (0x00200000));
577     return ((f1^f2) & 0x00200000) != 0;
578 #else
579     return 0;
580 #endif
581 }
582
583 /******************************************************************
584  *              dump_system_info
585  *
586  * Dumps into File the information about the system
587  */
588 static  unsigned        dump_system_info(struct dump_context* dc)
589 {
590     MINIDUMP_SYSTEM_INFO        mdSysInfo;
591     SYSTEM_INFO                 sysInfo;
592     OSVERSIONINFOW              osInfo;
593     DWORD                       written;
594     ULONG                       slen;
595     DWORD                       wine_extra = 0;
596
597     const char *(CDECL *wine_get_build_id)(void);
598     void (CDECL *wine_get_host_version)(const char **sysname, const char **release);
599     const char* build_id = NULL;
600     const char* sys_name = NULL;
601     const char* release_name = NULL;
602
603     GetSystemInfo(&sysInfo);
604     osInfo.dwOSVersionInfoSize = sizeof(osInfo);
605     GetVersionExW(&osInfo);
606
607     wine_get_build_id = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_build_id");
608     wine_get_host_version = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_host_version");
609     if (wine_get_build_id && wine_get_host_version)
610     {
611         /* cheat minidump system information by adding specific wine information */
612         wine_extra = 4 + 4 * sizeof(slen);
613         build_id = wine_get_build_id();
614         wine_get_host_version(&sys_name, &release_name);
615         wine_extra += strlen(build_id) + 1 + strlen(sys_name) + 1 + strlen(release_name) + 1;
616     }
617
618     mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture;
619     mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel;
620     mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision;
621     mdSysInfo.u.s.NumberOfProcessors = sysInfo.dwNumberOfProcessors;
622     mdSysInfo.u.s.ProductType = VER_NT_WORKSTATION; /* FIXME */
623     mdSysInfo.MajorVersion = osInfo.dwMajorVersion;
624     mdSysInfo.MinorVersion = osInfo.dwMinorVersion;
625     mdSysInfo.BuildNumber = osInfo.dwBuildNumber;
626     mdSysInfo.PlatformId = osInfo.dwPlatformId;
627
628     mdSysInfo.CSDVersionRva = dc->rva + sizeof(mdSysInfo) + wine_extra;
629     mdSysInfo.u1.Reserved1 = 0;
630     mdSysInfo.u1.s.SuiteMask = VER_SUITE_TERMINAL;
631
632     if (have_x86cpuid())
633     {
634         unsigned        regs0[4], regs1[4];
635
636         do_x86cpuid(0, regs0);
637         mdSysInfo.Cpu.X86CpuInfo.VendorId[0] = regs0[1];
638         mdSysInfo.Cpu.X86CpuInfo.VendorId[1] = regs0[2];
639         mdSysInfo.Cpu.X86CpuInfo.VendorId[2] = regs0[3];
640         do_x86cpuid(1, regs1);
641         mdSysInfo.Cpu.X86CpuInfo.VersionInformation = regs1[0];
642         mdSysInfo.Cpu.X86CpuInfo.FeatureInformation = regs1[3];
643         mdSysInfo.Cpu.X86CpuInfo.AMDExtendedCpuFeatures = 0;
644         if (regs0[1] == 0x68747541 /* "Auth" */ &&
645             regs0[3] == 0x69746e65 /* "enti" */ &&
646             regs0[2] == 0x444d4163 /* "cAMD" */)
647         {
648             do_x86cpuid(0x80000000, regs1);  /* get vendor cpuid level */
649             if (regs1[0] >= 0x80000001)
650             {
651                 do_x86cpuid(0x80000001, regs1);  /* get vendor features */
652                 mdSysInfo.Cpu.X86CpuInfo.AMDExtendedCpuFeatures = regs1[3];
653             }
654         }
655     }
656     else
657     {
658         unsigned        i;
659         ULONG64         one = 1;
660
661         mdSysInfo.Cpu.OtherCpuInfo.ProcessorFeatures[0] = 0;
662         mdSysInfo.Cpu.OtherCpuInfo.ProcessorFeatures[1] = 0;
663
664         for (i = 0; i < sizeof(mdSysInfo.Cpu.OtherCpuInfo.ProcessorFeatures[0]) * 8; i++)
665             if (IsProcessorFeaturePresent(i))
666                 mdSysInfo.Cpu.OtherCpuInfo.ProcessorFeatures[0] |= one << i;
667     }
668     append(dc, &mdSysInfo, sizeof(mdSysInfo));
669
670     /* write Wine specific system information just behind the structure, and before any string */
671     if (wine_extra)
672     {
673         char code[] = {'W','I','N','E'};
674
675         WriteFile(dc->hFile, code, 4, &written, NULL);
676         /* number of sub-info, so that we can extend structure if needed */
677         slen = 3;
678         WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
679         /* we store offsets from just after the WINE marker */
680         slen = 4 * sizeof(DWORD);
681         WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
682         slen += strlen(build_id) + 1;
683         WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
684         slen += strlen(sys_name) + 1;
685         WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
686         WriteFile(dc->hFile, build_id, strlen(build_id) + 1, &written, NULL);
687         WriteFile(dc->hFile, sys_name, strlen(sys_name) + 1, &written, NULL);
688         WriteFile(dc->hFile, release_name, strlen(release_name) + 1, &written, NULL);
689         dc->rva += wine_extra;
690     }
691
692     /* write the service pack version string after this stream.  It is referenced within the
693        stream by its RVA in the file. */
694     slen = lstrlenW(osInfo.szCSDVersion) * sizeof(WCHAR);
695     WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
696     WriteFile(dc->hFile, osInfo.szCSDVersion, slen, &written, NULL);
697     dc->rva += sizeof(ULONG) + slen;
698
699     return sizeof(mdSysInfo);
700 }
701
702 /******************************************************************
703  *              dump_threads
704  *
705  * Dumps into File the information about running threads
706  */
707 static  unsigned        dump_threads(struct dump_context* dc,
708                                      const MINIDUMP_EXCEPTION_INFORMATION* except)
709 {
710     MINIDUMP_THREAD             mdThd;
711     MINIDUMP_THREAD_LIST        mdThdList;
712     unsigned                    i, sz;
713     RVA                         rva_base;
714     DWORD                       flags_out;
715     CONTEXT                     ctx;
716
717     mdThdList.NumberOfThreads = 0;
718
719     rva_base = dc->rva;
720     dc->rva += sz = sizeof(mdThdList.NumberOfThreads) + dc->num_threads * sizeof(mdThd);
721
722     for (i = 0; i < dc->num_threads; i++)
723     {
724         fetch_thread_info(dc, i, except, &mdThd, &ctx);
725
726         flags_out = ThreadWriteThread | ThreadWriteStack | ThreadWriteContext |
727             ThreadWriteInstructionWindow;
728         if (dc->type & MiniDumpWithProcessThreadData)
729             flags_out |= ThreadWriteThreadData;
730         if (dc->type & MiniDumpWithThreadInfo)
731             flags_out |= ThreadWriteThreadInfo;
732
733         if (dc->cb)
734         {
735             MINIDUMP_CALLBACK_INPUT     cbin;
736             MINIDUMP_CALLBACK_OUTPUT    cbout;
737
738             cbin.ProcessId = dc->pid;
739             cbin.ProcessHandle = dc->hProcess;
740             cbin.CallbackType = ThreadCallback;
741             cbin.u.Thread.ThreadId = dc->threads[i].tid;
742             cbin.u.Thread.ThreadHandle = 0; /* FIXME */
743             cbin.u.Thread.Context = ctx;
744             cbin.u.Thread.SizeOfContext = sizeof(CONTEXT);
745             cbin.u.Thread.StackBase = mdThd.Stack.StartOfMemoryRange;
746             cbin.u.Thread.StackEnd = mdThd.Stack.StartOfMemoryRange +
747                 mdThd.Stack.Memory.DataSize;
748
749             cbout.u.ThreadWriteFlags = flags_out;
750             if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
751                 continue;
752             flags_out &= cbout.u.ThreadWriteFlags;
753         }
754         if (flags_out & ThreadWriteThread)
755         {
756             if (ctx.ContextFlags && (flags_out & ThreadWriteContext))
757             {
758                 mdThd.ThreadContext.Rva = dc->rva;
759                 mdThd.ThreadContext.DataSize = sizeof(CONTEXT);
760                 append(dc, &ctx, sizeof(CONTEXT));
761             }
762             if (mdThd.Stack.Memory.DataSize && (flags_out & ThreadWriteStack))
763             {
764                 minidump_add_memory_block(dc, mdThd.Stack.StartOfMemoryRange,
765                                           mdThd.Stack.Memory.DataSize,
766                                           rva_base + sizeof(mdThdList.NumberOfThreads) +
767                                           mdThdList.NumberOfThreads * sizeof(mdThd) +
768                                           FIELD_OFFSET(MINIDUMP_THREAD, Stack.Memory.Rva));
769             }
770             writeat(dc, 
771                     rva_base + sizeof(mdThdList.NumberOfThreads) +
772                         mdThdList.NumberOfThreads * sizeof(mdThd),
773                     &mdThd, sizeof(mdThd));
774             mdThdList.NumberOfThreads++;
775         }
776         /* fetch CPU dependent thread info (like 256 bytes around program counter */
777         dbghelp_current_cpu->fetch_minidump_thread(dc, i, flags_out, &ctx);
778     }
779     writeat(dc, rva_base,
780             &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads));
781
782     return sz;
783 }
784
785 /******************************************************************
786  *              dump_memory_info
787  *
788  * dumps information about the memory of the process (stack of the threads)
789  */
790 static unsigned         dump_memory_info(struct dump_context* dc)
791 {
792     MINIDUMP_MEMORY_LIST        mdMemList;
793     MINIDUMP_MEMORY_DESCRIPTOR  mdMem;
794     DWORD                       written;
795     unsigned                    i, pos, len, sz;
796     RVA                         rva_base;
797     char                        tmp[1024];
798
799     mdMemList.NumberOfMemoryRanges = dc->num_mem;
800     append(dc, &mdMemList.NumberOfMemoryRanges,
801            sizeof(mdMemList.NumberOfMemoryRanges));
802     rva_base = dc->rva;
803     sz = mdMemList.NumberOfMemoryRanges * sizeof(mdMem);
804     dc->rva += sz;
805     sz += sizeof(mdMemList.NumberOfMemoryRanges);
806
807     for (i = 0; i < dc->num_mem; i++)
808     {
809         mdMem.StartOfMemoryRange = dc->mem[i].base;
810         mdMem.Memory.Rva = dc->rva;
811         mdMem.Memory.DataSize = dc->mem[i].size;
812         SetFilePointer(dc->hFile, dc->rva, NULL, FILE_BEGIN);
813         for (pos = 0; pos < dc->mem[i].size; pos += sizeof(tmp))
814         {
815             len = min(dc->mem[i].size - pos, sizeof(tmp));
816             if (ReadProcessMemory(dc->hProcess, 
817                                   (void*)(DWORD_PTR)(dc->mem[i].base + pos),
818                                   tmp, len, NULL))
819                 WriteFile(dc->hFile, tmp, len, &written, NULL);
820         }
821         dc->rva += mdMem.Memory.DataSize;
822         writeat(dc, rva_base + i * sizeof(mdMem), &mdMem, sizeof(mdMem));
823         if (dc->mem[i].rva)
824         {
825             writeat(dc, dc->mem[i].rva, &mdMem.Memory.Rva, sizeof(mdMem.Memory.Rva));
826         }
827     }
828
829     return sz;
830 }
831
832 static unsigned         dump_misc_info(struct dump_context* dc)
833 {
834     MINIDUMP_MISC_INFO  mmi;
835
836     mmi.SizeOfInfo = sizeof(mmi);
837     mmi.Flags1 = MINIDUMP_MISC1_PROCESS_ID;
838     mmi.ProcessId = dc->pid;
839     /* FIXME: create/user/kernel time */
840     mmi.ProcessCreateTime = 0;
841     mmi.ProcessKernelTime = 0;
842     mmi.ProcessUserTime = 0;
843
844     append(dc, &mmi, sizeof(mmi));
845     return sizeof(mmi);
846 }
847
848 /******************************************************************
849  *              MiniDumpWriteDump (DEBUGHLP.@)
850  *
851  */
852 BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
853                               MINIDUMP_TYPE DumpType,
854                               PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
855                               PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
856                               PMINIDUMP_CALLBACK_INFORMATION CallbackParam)
857 {
858     static const MINIDUMP_DIRECTORY emptyDir = {UnusedStream, {0, 0}};
859     MINIDUMP_HEADER     mdHead;
860     MINIDUMP_DIRECTORY  mdDir;
861     DWORD               i, nStreams, idx_stream;
862     struct dump_context dc;
863
864     dc.hProcess = hProcess;
865     dc.hFile = hFile;
866     dc.pid = pid;
867     dc.modules = NULL;
868     dc.num_modules = 0;
869     dc.alloc_modules = 0;
870     dc.threads = NULL;
871     dc.num_threads = 0;
872     dc.cb = CallbackParam;
873     dc.type = DumpType;
874     dc.mem = NULL;
875     dc.num_mem = 0;
876     dc.alloc_mem = 0;
877     dc.rva = 0;
878
879     if (!fetch_process_info(&dc)) return FALSE;
880     fetch_modules_info(&dc);
881
882     /* 1) init */
883     nStreams = 6 + (ExceptionParam ? 1 : 0) +
884         (UserStreamParam ? UserStreamParam->UserStreamCount : 0);
885
886     /* pad the directory size to a multiple of 4 for alignment purposes */
887     nStreams = (nStreams + 3) & ~3;
888
889     if (DumpType & MiniDumpWithDataSegs)
890         FIXME("NIY MiniDumpWithDataSegs\n");
891     if (DumpType & MiniDumpWithFullMemory)
892         FIXME("NIY MiniDumpWithFullMemory\n");
893     if (DumpType & MiniDumpWithHandleData)
894         FIXME("NIY MiniDumpWithHandleData\n");
895     if (DumpType & MiniDumpFilterMemory)
896         FIXME("NIY MiniDumpFilterMemory\n");
897     if (DumpType & MiniDumpScanMemory)
898         FIXME("NIY MiniDumpScanMemory\n");
899
900     /* 2) write header */
901     mdHead.Signature = MINIDUMP_SIGNATURE;
902     mdHead.Version = MINIDUMP_VERSION;  /* NOTE: native puts in an 'implementation specific' value in the high order word of this member */
903     mdHead.NumberOfStreams = nStreams;
904     mdHead.CheckSum = 0;                /* native sets a 0 checksum in its files */
905     mdHead.StreamDirectoryRva = sizeof(mdHead);
906     mdHead.u.TimeDateStamp = time(NULL);
907     mdHead.Flags = DumpType;
908     append(&dc, &mdHead, sizeof(mdHead));
909
910     /* 3) write stream directories */
911     dc.rva += nStreams * sizeof(mdDir);
912     idx_stream = 0;
913
914     /* 3.1) write data stream directories */
915
916     /* must be first in minidump */
917     mdDir.StreamType = SystemInfoStream;
918     mdDir.Location.Rva = dc.rva;
919     mdDir.Location.DataSize = dump_system_info(&dc);
920     writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
921             &mdDir, sizeof(mdDir));
922
923     mdDir.StreamType = ThreadListStream;
924     mdDir.Location.Rva = dc.rva;
925     mdDir.Location.DataSize = dump_threads(&dc, ExceptionParam);
926     writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), 
927             &mdDir, sizeof(mdDir));
928
929     mdDir.StreamType = ModuleListStream;
930     mdDir.Location.Rva = dc.rva;
931     mdDir.Location.DataSize = dump_modules(&dc, FALSE);
932     writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
933             &mdDir, sizeof(mdDir));
934
935     mdDir.StreamType = 0xfff0; /* FIXME: this is part of MS reserved streams */
936     mdDir.Location.Rva = dc.rva;
937     mdDir.Location.DataSize = dump_modules(&dc, TRUE);
938     writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
939             &mdDir, sizeof(mdDir));
940
941     mdDir.StreamType = MemoryListStream;
942     mdDir.Location.Rva = dc.rva;
943     mdDir.Location.DataSize = dump_memory_info(&dc);
944     writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
945             &mdDir, sizeof(mdDir));
946
947     mdDir.StreamType = MiscInfoStream;
948     mdDir.Location.Rva = dc.rva;
949     mdDir.Location.DataSize = dump_misc_info(&dc);
950     writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
951             &mdDir, sizeof(mdDir));
952
953     /* 3.2) write exception information (if any) */
954     if (ExceptionParam)
955     {
956         mdDir.StreamType = ExceptionStream;
957         mdDir.Location.Rva = dc.rva;
958         mdDir.Location.DataSize = dump_exception_info(&dc, ExceptionParam);
959         writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
960                 &mdDir, sizeof(mdDir));
961     }
962
963     /* 3.3) write user defined streams (if any) */
964     if (UserStreamParam)
965     {
966         for (i = 0; i < UserStreamParam->UserStreamCount; i++)
967         {
968             mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type;
969             mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize;
970             mdDir.Location.Rva = dc.rva;
971             writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
972                     &mdDir, sizeof(mdDir));
973             append(&dc, UserStreamParam->UserStreamArray[i].Buffer, 
974                    UserStreamParam->UserStreamArray[i].BufferSize);
975         }
976     }
977
978     /* fill the remaining directory entries with 0's (unused stream types) */
979     /* NOTE: this should always come last in the dump! */
980     for (i = idx_stream; i < nStreams; i++)
981         writeat(&dc, mdHead.StreamDirectoryRva + i * sizeof(emptyDir), &emptyDir, sizeof(emptyDir));
982
983     HeapFree(GetProcessHeap(), 0, dc.mem);
984     HeapFree(GetProcessHeap(), 0, dc.modules);
985     HeapFree(GetProcessHeap(), 0, dc.threads);
986
987     return TRUE;
988 }
989
990 /******************************************************************
991  *              MiniDumpReadDumpStream (DEBUGHLP.@)
992  *
993  *
994  */
995 BOOL WINAPI MiniDumpReadDumpStream(PVOID base, ULONG str_idx,
996                                    PMINIDUMP_DIRECTORY* pdir,
997                                    PVOID* stream, ULONG* size)
998 {
999     MINIDUMP_HEADER*    mdHead = base;
1000
1001     if (mdHead->Signature == MINIDUMP_SIGNATURE)
1002     {
1003         MINIDUMP_DIRECTORY* dir;
1004         DWORD               i;
1005
1006         dir = (MINIDUMP_DIRECTORY*)((char*)base + mdHead->StreamDirectoryRva);
1007         for (i = 0; i < mdHead->NumberOfStreams; i++, dir++)
1008         {
1009             if (dir->StreamType == str_idx)
1010             {
1011                 if (pdir) *pdir = dir;
1012                 if (stream) *stream = (char*)base + dir->Location.Rva;
1013                 if (size) *size = dir->Location.DataSize;
1014                 return TRUE;
1015             }
1016         }
1017     }
1018     SetLastError(ERROR_INVALID_PARAMETER);
1019     return FALSE;
1020 }