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