ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

minidump.c
Go to the documentation of this file.
00001 /*
00002  * File minidump.c - management of dumps (read & write)
00003  *
00004  * Copyright (C) 2004-2005, Eric Pouech
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  */
00020 
00021 #include <time.h>
00022 
00023 #define NONAMELESSUNION
00024 #define NONAMELESSSTRUCT
00025 
00026 #include "ntstatus.h"
00027 #define WIN32_NO_STATUS
00028 #include "dbghelp_private.h"
00029 #include "winternl.h"
00030 #include "psapi.h"
00031 #include "wine/debug.h"
00032 
00033 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
00034 
00035 struct dump_memory
00036 {
00037     ULONG64                             base;
00038     ULONG                               size;
00039     ULONG                               rva;
00040 };
00041 
00042 struct dump_module
00043 {
00044     unsigned                            is_elf;
00045     ULONG64                             base;
00046     ULONG                               size;
00047     DWORD                               timestamp;
00048     DWORD                               checksum;
00049     WCHAR                               name[MAX_PATH];
00050 };
00051 
00052 struct dump_context
00053 {
00054     /* process & thread information */
00055     HANDLE                              hProcess;
00056     DWORD                               pid;
00057     void*                               pcs_buffer;
00058     SYSTEM_PROCESS_INFORMATION*         spi;
00059     /* module information */
00060     struct dump_module*                 modules;
00061     unsigned                            num_modules;
00062     unsigned                            alloc_modules;
00063     /* exception information */
00064     /* output information */
00065     MINIDUMP_TYPE                       type;
00066     HANDLE                              hFile;
00067     RVA                                 rva;
00068     struct dump_memory*                 mem;
00069     unsigned                            num_mem;
00070     unsigned                            alloc_mem;
00071     /* callback information */
00072     MINIDUMP_CALLBACK_INFORMATION*      cb;
00073 };
00074 
00075 /******************************************************************
00076  *      fetch_processes_info
00077  *
00078  * reads system wide process information, and make spi point to the record
00079  * for process of id 'pid'
00080  */
00081 static BOOL fetch_processes_info(struct dump_context* dc)
00082 {
00083     ULONG       buf_size = 0x1000;
00084     NTSTATUS    nts;
00085 
00086     dc->pcs_buffer = NULL;
00087     if (!(dc->pcs_buffer = HeapAlloc(GetProcessHeap(), 0, buf_size))) return FALSE;
00088     for (;;)
00089     {
00090         nts = NtQuerySystemInformation(SystemProcessInformation, 
00091                                        dc->pcs_buffer, buf_size, NULL);
00092         if (nts != STATUS_INFO_LENGTH_MISMATCH) break;
00093         dc->pcs_buffer = HeapReAlloc(GetProcessHeap(), 0, dc->pcs_buffer, 
00094                                      buf_size *= 2);
00095         if (!dc->pcs_buffer) return FALSE;
00096     }
00097 
00098     if (nts == STATUS_SUCCESS)
00099     {
00100         dc->spi = dc->pcs_buffer;
00101         for (;;)
00102         {
00103             if (HandleToUlong(dc->spi->UniqueProcessId) == dc->pid) return TRUE;
00104             if (!dc->spi->NextEntryOffset) break;
00105             dc->spi = (SYSTEM_PROCESS_INFORMATION*)((char*)dc->spi + dc->spi->NextEntryOffset);
00106         }
00107     }
00108     HeapFree(GetProcessHeap(), 0, dc->pcs_buffer);
00109     dc->pcs_buffer = NULL;
00110     dc->spi = NULL;
00111     return FALSE;
00112 }
00113 
00114 static void fetch_thread_stack(struct dump_context* dc, const void* teb_addr,
00115                                const CONTEXT* ctx, MINIDUMP_MEMORY_DESCRIPTOR* mmd)
00116 {
00117     NT_TIB      tib;
00118     ADDRESS64   addr;
00119 
00120     if (ReadProcessMemory(dc->hProcess, teb_addr, &tib, sizeof(tib), NULL) &&
00121         dbghelp_current_cpu &&
00122         dbghelp_current_cpu->get_addr(NULL /* FIXME */, ctx, cpu_addr_stack, &addr) && addr.Mode == AddrModeFlat)
00123     {
00124         if (addr.Offset)
00125         {
00126             addr.Offset -= dbghelp_current_cpu->word_size;
00127             /* make sure stack pointer is within the established range of the stack.  It could have
00128                been clobbered by whatever caused the original exception. */
00129             if (addr.Offset < (ULONG_PTR)tib.StackLimit || addr.Offset > (ULONG_PTR)tib.StackBase)
00130                 mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
00131 
00132             else
00133                 mmd->StartOfMemoryRange = addr.Offset;
00134         }
00135         else
00136             mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
00137         mmd->Memory.DataSize = (ULONG_PTR)tib.StackBase - mmd->StartOfMemoryRange;
00138     }
00139 }
00140 
00141 /******************************************************************
00142  *      fetch_thread_info
00143  *
00144  * fetches some information about thread of id 'tid'
00145  */
00146 static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx,
00147                               const MINIDUMP_EXCEPTION_INFORMATION* except,
00148                               MINIDUMP_THREAD* mdThd, CONTEXT* ctx)
00149 {
00150     DWORD                       tid = HandleToUlong(dc->spi->ti[thd_idx].ClientId.UniqueThread);
00151     HANDLE                      hThread;
00152     THREAD_BASIC_INFORMATION    tbi;
00153 
00154     memset(ctx, 0, sizeof(*ctx));
00155 
00156     mdThd->ThreadId = tid;
00157     mdThd->SuspendCount = 0;
00158     mdThd->Teb = 0;
00159     mdThd->Stack.StartOfMemoryRange = 0;
00160     mdThd->Stack.Memory.DataSize = 0;
00161     mdThd->Stack.Memory.Rva = 0;
00162     mdThd->ThreadContext.DataSize = 0;
00163     mdThd->ThreadContext.Rva = 0;
00164     mdThd->PriorityClass = dc->spi->ti[thd_idx].dwBasePriority; /* FIXME */
00165     mdThd->Priority = dc->spi->ti[thd_idx].dwCurrentPriority;
00166 
00167     if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL)
00168     {
00169         FIXME("Couldn't open thread %u (%u)\n", tid, GetLastError());
00170         return FALSE;
00171     }
00172     
00173     if (NtQueryInformationThread(hThread, ThreadBasicInformation,
00174                                  &tbi, sizeof(tbi), NULL) == STATUS_SUCCESS)
00175     {
00176         mdThd->Teb = (ULONG_PTR)tbi.TebBaseAddress;
00177         if (tbi.ExitStatus == STILL_ACTIVE)
00178         {
00179             if (tid != GetCurrentThreadId() &&
00180                 (mdThd->SuspendCount = SuspendThread(hThread)) != (DWORD)-1)
00181             {
00182                 ctx->ContextFlags = CONTEXT_FULL;
00183                 if (!GetThreadContext(hThread, ctx))
00184                     memset(ctx, 0, sizeof(*ctx));
00185 
00186                 fetch_thread_stack(dc, tbi.TebBaseAddress, ctx, &mdThd->Stack);
00187                 ResumeThread(hThread);
00188             }
00189             else if (tid == GetCurrentThreadId() && except)
00190             {
00191                 CONTEXT lctx, *pctx;
00192                 mdThd->SuspendCount = 1;
00193                 if (except->ClientPointers)
00194                 {
00195                     EXCEPTION_POINTERS      ep;
00196 
00197                     ReadProcessMemory(dc->hProcess, except->ExceptionPointers,
00198                                       &ep, sizeof(ep), NULL);
00199                     ReadProcessMemory(dc->hProcess, ep.ContextRecord,
00200                                       &lctx, sizeof(lctx), NULL);
00201                     pctx = &lctx;
00202                 }
00203                 else pctx = except->ExceptionPointers->ContextRecord;
00204 
00205                 *ctx = *pctx;
00206                 fetch_thread_stack(dc, tbi.TebBaseAddress, pctx, &mdThd->Stack);
00207             }
00208             else mdThd->SuspendCount = 0;
00209         }
00210     }
00211     CloseHandle(hThread);
00212     return TRUE;
00213 }
00214 
00215 /******************************************************************
00216  *      add_module
00217  *
00218  * Add a module to a dump context
00219  */
00220 static BOOL add_module(struct dump_context* dc, const WCHAR* name,
00221                        DWORD64 base, DWORD size, DWORD timestamp, DWORD checksum,
00222                        BOOL is_elf)
00223 {
00224     if (!dc->modules)
00225     {
00226         dc->alloc_modules = 32;
00227         dc->modules = HeapAlloc(GetProcessHeap(), 0,
00228                                 dc->alloc_modules * sizeof(*dc->modules));
00229     }
00230     else if(dc->num_modules >= dc->alloc_modules)
00231     {
00232         dc->alloc_modules *= 2;
00233         dc->modules = HeapReAlloc(GetProcessHeap(), 0, dc->modules,
00234                                   dc->alloc_modules * sizeof(*dc->modules));
00235     }
00236     if (!dc->modules)
00237     {
00238         dc->alloc_modules = dc->num_modules = 0;
00239         return FALSE;
00240     }
00241     if (is_elf ||
00242         !GetModuleFileNameExW(dc->hProcess, (HMODULE)(DWORD_PTR)base,
00243                               dc->modules[dc->num_modules].name,
00244                               sizeof(dc->modules[dc->num_modules].name) / sizeof(WCHAR)))
00245         lstrcpynW(dc->modules[dc->num_modules].name, name,
00246                   sizeof(dc->modules[dc->num_modules].name) / sizeof(WCHAR));
00247     dc->modules[dc->num_modules].base = base;
00248     dc->modules[dc->num_modules].size = size;
00249     dc->modules[dc->num_modules].timestamp = timestamp;
00250     dc->modules[dc->num_modules].checksum = checksum;
00251     dc->modules[dc->num_modules].is_elf = is_elf;
00252     dc->num_modules++;
00253 
00254     return TRUE;
00255 }
00256 
00257 /******************************************************************
00258  *      fetch_pe_module_info_cb
00259  *
00260  * Callback for accumulating in dump_context a PE modules set
00261  */
00262 static BOOL WINAPI fetch_pe_module_info_cb(PCWSTR name, DWORD64 base, ULONG size,
00263                                            PVOID user)
00264 {
00265     struct dump_context*        dc = user;
00266     IMAGE_NT_HEADERS            nth;
00267 
00268     if (!validate_addr64(base)) return FALSE;
00269 
00270     if (pe_load_nt_header(dc->hProcess, base, &nth))
00271         add_module(user, name, base, size,
00272                    nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum,
00273                    FALSE);
00274     return TRUE;
00275 }
00276 
00277 /******************************************************************
00278  *      fetch_elf_module_info_cb
00279  *
00280  * Callback for accumulating in dump_context an ELF modules set
00281  */
00282 static BOOL fetch_elf_module_info_cb(const WCHAR* name, unsigned long base,
00283                                      void* user)
00284 {
00285     struct dump_context*        dc = user;
00286     DWORD_PTR                   rbase;
00287     DWORD                       size, checksum;
00288 
00289     /* FIXME: there's no relevant timestamp on ELF modules */
00290     /* NB: if we have a non-null base from the live-target use it (whenever
00291      * the ELF module is relocatable or not). If we have a null base (ELF
00292      * module isn't relocatable) then grab its base address from ELF file
00293      */
00294     if (!elf_fetch_file_info(name, &rbase, &size, &checksum))
00295         size = checksum = 0;
00296     add_module(dc, name, base ? base : rbase, size, 0 /* FIXME */, checksum, TRUE);
00297     return TRUE;
00298 }
00299 
00300 /******************************************************************
00301  *      fetch_macho_module_info_cb
00302  *
00303  * Callback for accumulating in dump_context a Mach-O modules set
00304  */
00305 static BOOL fetch_macho_module_info_cb(const WCHAR* name, unsigned long base,
00306                                        void* user)
00307 {
00308     struct dump_context*        dc = (struct dump_context*)user;
00309     DWORD_PTR                   rbase;
00310     DWORD                       size, checksum;
00311 
00312     /* FIXME: there's no relevant timestamp on Mach-O modules */
00313     /* NB: if we have a non-null base from the live-target use it.  If we have
00314      * a null base, then grab its base address from Mach-O file.
00315      */
00316     if (!macho_fetch_file_info(name, &rbase, &size, &checksum))
00317         size = checksum = 0;
00318     add_module(dc, name, base ? base : rbase, size, 0 /* FIXME */, checksum, TRUE);
00319     return TRUE;
00320 }
00321 
00322 static void fetch_modules_info(struct dump_context* dc)
00323 {
00324     EnumerateLoadedModulesW64(dc->hProcess, fetch_pe_module_info_cb, dc);
00325     /* Since we include ELF modules in a separate stream from the regular PE ones,
00326      * we can always include those ELF modules (they don't eat lots of space)
00327      * And it's always a good idea to have a trace of the loaded ELF modules for
00328      * a given application in a post mortem debugging condition.
00329      */
00330     elf_enum_modules(dc->hProcess, fetch_elf_module_info_cb, dc);
00331     macho_enum_modules(dc->hProcess, fetch_macho_module_info_cb, dc);
00332 }
00333 
00334 static void fetch_module_versioninfo(LPCWSTR filename, VS_FIXEDFILEINFO* ffi)
00335 {
00336     DWORD       handle;
00337     DWORD       sz;
00338     static const WCHAR backslashW[] = {'\\', '\0'};
00339 
00340     memset(ffi, 0, sizeof(*ffi));
00341     if ((sz = GetFileVersionInfoSizeW(filename, &handle)))
00342     {
00343         void*   info = HeapAlloc(GetProcessHeap(), 0, sz);
00344         if (info && GetFileVersionInfoW(filename, handle, sz, info))
00345         {
00346             VS_FIXEDFILEINFO*   ptr;
00347             UINT    len;
00348 
00349             if (VerQueryValueW(info, backslashW, (void*)&ptr, &len))
00350                 memcpy(ffi, ptr, min(len, sizeof(*ffi)));
00351         }
00352         HeapFree(GetProcessHeap(), 0, info);
00353     }
00354 }
00355 
00356 /******************************************************************
00357  *      add_memory_block
00358  *
00359  * Add a memory block to be dumped in a minidump
00360  * If rva is non 0, it's the rva in the minidump where has to be stored
00361  * also the rva of the memory block when written (this allows to reference
00362  * a memory block from outside the list of memory blocks).
00363  */
00364 static void add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva)
00365 {
00366     if (!dc->mem)
00367     {
00368         dc->alloc_mem = 32;
00369         dc->mem = HeapAlloc(GetProcessHeap(), 0, dc->alloc_mem * sizeof(*dc->mem));
00370     }
00371     else if (dc->num_mem >= dc->alloc_mem)
00372     {
00373         dc->alloc_mem *= 2;
00374         dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem,
00375                               dc->alloc_mem * sizeof(*dc->mem));
00376     }
00377     if (dc->mem)
00378     {
00379         dc->mem[dc->num_mem].base = base;
00380         dc->mem[dc->num_mem].size = size;
00381         dc->mem[dc->num_mem].rva  = rva;
00382         dc->num_mem++;
00383     }
00384     else dc->num_mem = dc->alloc_mem = 0;
00385 }
00386 
00387 /******************************************************************
00388  *      writeat
00389  *
00390  * Writes a chunk of data at a given position in the minidump
00391  */
00392 static void writeat(struct dump_context* dc, RVA rva, const void* data, unsigned size)
00393 {
00394     DWORD       written;
00395 
00396     SetFilePointer(dc->hFile, rva, NULL, FILE_BEGIN);
00397     WriteFile(dc->hFile, data, size, &written, NULL);
00398 }
00399 
00400 /******************************************************************
00401  *      append
00402  *
00403  * writes a new chunk of data to the minidump, increasing the current
00404  * rva in dc
00405  */
00406 static void append(struct dump_context* dc, const void* data, unsigned size)
00407 {
00408     writeat(dc, dc->rva, data, size);
00409     dc->rva += size;
00410 }
00411 
00412 /******************************************************************
00413  *      dump_exception_info
00414  *
00415  * Write in File the exception information from pcs
00416  */
00417 static  unsigned        dump_exception_info(struct dump_context* dc,
00418                                             const MINIDUMP_EXCEPTION_INFORMATION* except)
00419 {
00420     MINIDUMP_EXCEPTION_STREAM   mdExcpt;
00421     EXCEPTION_RECORD            rec, *prec;
00422     CONTEXT                     ctx, *pctx;
00423     DWORD                       i;
00424 
00425     mdExcpt.ThreadId = except->ThreadId;
00426     mdExcpt.__alignment = 0;
00427     if (except->ClientPointers)
00428     {
00429         EXCEPTION_POINTERS      ep;
00430 
00431         ReadProcessMemory(dc->hProcess, 
00432                           except->ExceptionPointers, &ep, sizeof(ep), NULL);
00433         ReadProcessMemory(dc->hProcess, 
00434                           ep.ExceptionRecord, &rec, sizeof(rec), NULL);
00435         ReadProcessMemory(dc->hProcess, 
00436                           ep.ContextRecord, &ctx, sizeof(ctx), NULL);
00437         prec = &rec;
00438         pctx = &ctx;
00439     }
00440     else
00441     {
00442         prec = except->ExceptionPointers->ExceptionRecord;
00443         pctx = except->ExceptionPointers->ContextRecord;
00444     }
00445     mdExcpt.ExceptionRecord.ExceptionCode = prec->ExceptionCode;
00446     mdExcpt.ExceptionRecord.ExceptionFlags = prec->ExceptionFlags;
00447     mdExcpt.ExceptionRecord.ExceptionRecord = (DWORD_PTR)prec->ExceptionRecord;
00448     mdExcpt.ExceptionRecord.ExceptionAddress = (DWORD_PTR)prec->ExceptionAddress;
00449     mdExcpt.ExceptionRecord.NumberParameters = prec->NumberParameters;
00450     mdExcpt.ExceptionRecord.__unusedAlignment = 0;
00451     for (i = 0; i < mdExcpt.ExceptionRecord.NumberParameters; i++)
00452         mdExcpt.ExceptionRecord.ExceptionInformation[i] = prec->ExceptionInformation[i];
00453     mdExcpt.ThreadContext.DataSize = sizeof(*pctx);
00454     mdExcpt.ThreadContext.Rva = dc->rva + sizeof(mdExcpt);
00455 
00456     append(dc, &mdExcpt, sizeof(mdExcpt));
00457     append(dc, pctx, sizeof(*pctx));
00458     return sizeof(mdExcpt);
00459 }
00460 
00461 /******************************************************************
00462  *      dump_modules
00463  *
00464  * Write in File the modules from pcs
00465  */
00466 static  unsigned        dump_modules(struct dump_context* dc, BOOL dump_elf)
00467 {
00468     MINIDUMP_MODULE             mdModule;
00469     MINIDUMP_MODULE_LIST        mdModuleList;
00470     char                        tmp[1024];
00471     MINIDUMP_STRING*            ms = (MINIDUMP_STRING*)tmp;
00472     ULONG                       i, nmod;
00473     RVA                         rva_base;
00474     DWORD                       flags_out;
00475     unsigned                    sz;
00476 
00477     for (i = nmod = 0; i < dc->num_modules; i++)
00478     {
00479         if ((dc->modules[i].is_elf && dump_elf) ||
00480             (!dc->modules[i].is_elf && !dump_elf))
00481             nmod++;
00482     }
00483 
00484     mdModuleList.NumberOfModules = 0;
00485     /* reserve space for mdModuleList
00486      * FIXME: since we don't support 0 length arrays, we cannot use the
00487      * size of mdModuleList
00488      * FIXME: if we don't ask for all modules in cb, we'll get a hole in the file
00489      */
00490 
00491     /* the stream size is just the size of the module index.  It does not include the data for the
00492        names of each module.  *Technically* the names are supposed to go into the common string table
00493        in the minidump file.  Since each string is referenced by RVA they can all safely be located
00494        anywhere between streams in the file, so the end of this stream is sufficient. */
00495     rva_base = dc->rva;
00496     dc->rva += sz = sizeof(mdModuleList.NumberOfModules) + sizeof(mdModule) * nmod;
00497     for (i = 0; i < dc->num_modules; i++)
00498     {
00499         if ((dc->modules[i].is_elf && !dump_elf) ||
00500             (!dc->modules[i].is_elf && dump_elf))
00501             continue;
00502 
00503         flags_out = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteCvRecord;
00504         if (dc->type & MiniDumpWithDataSegs)
00505             flags_out |= ModuleWriteDataSeg;
00506         if (dc->type & MiniDumpWithProcessThreadData)
00507             flags_out |= ModuleWriteTlsData;
00508         if (dc->type & MiniDumpWithCodeSegs)
00509             flags_out |= ModuleWriteCodeSegs;
00510         ms->Length = (lstrlenW(dc->modules[i].name) + 1) * sizeof(WCHAR);
00511         if (sizeof(ULONG) + ms->Length > sizeof(tmp))
00512             FIXME("Buffer overflow!!!\n");
00513         lstrcpyW(ms->Buffer, dc->modules[i].name);
00514 
00515         if (dc->cb)
00516         {
00517             MINIDUMP_CALLBACK_INPUT     cbin;
00518             MINIDUMP_CALLBACK_OUTPUT    cbout;
00519 
00520             cbin.ProcessId = dc->pid;
00521             cbin.ProcessHandle = dc->hProcess;
00522             cbin.CallbackType = ModuleCallback;
00523 
00524             cbin.u.Module.FullPath = ms->Buffer;
00525             cbin.u.Module.BaseOfImage = dc->modules[i].base;
00526             cbin.u.Module.SizeOfImage = dc->modules[i].size;
00527             cbin.u.Module.CheckSum = dc->modules[i].checksum;
00528             cbin.u.Module.TimeDateStamp = dc->modules[i].timestamp;
00529             memset(&cbin.u.Module.VersionInfo, 0, sizeof(cbin.u.Module.VersionInfo));
00530             cbin.u.Module.CvRecord = NULL;
00531             cbin.u.Module.SizeOfCvRecord = 0;
00532             cbin.u.Module.MiscRecord = NULL;
00533             cbin.u.Module.SizeOfMiscRecord = 0;
00534 
00535             cbout.u.ModuleWriteFlags = flags_out;
00536             if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
00537                 continue;
00538             flags_out &= cbout.u.ModuleWriteFlags;
00539         }
00540         if (flags_out & ModuleWriteModule)
00541         {
00542             mdModule.BaseOfImage = dc->modules[i].base;
00543             mdModule.SizeOfImage = dc->modules[i].size;
00544             mdModule.CheckSum = dc->modules[i].checksum;
00545             mdModule.TimeDateStamp = dc->modules[i].timestamp;
00546             mdModule.ModuleNameRva = dc->rva;
00547             ms->Length -= sizeof(WCHAR);
00548             append(dc, ms, sizeof(ULONG) + ms->Length + sizeof(WCHAR));
00549             fetch_module_versioninfo(ms->Buffer, &mdModule.VersionInfo);
00550             mdModule.CvRecord.DataSize = 0; /* FIXME */
00551             mdModule.CvRecord.Rva = 0; /* FIXME */
00552             mdModule.MiscRecord.DataSize = 0; /* FIXME */
00553             mdModule.MiscRecord.Rva = 0; /* FIXME */
00554             mdModule.Reserved0 = 0; /* FIXME */
00555             mdModule.Reserved1 = 0; /* FIXME */
00556             writeat(dc,
00557                     rva_base + sizeof(mdModuleList.NumberOfModules) + 
00558                         mdModuleList.NumberOfModules++ * sizeof(mdModule), 
00559                     &mdModule, sizeof(mdModule));
00560         }
00561     }
00562     writeat(dc, rva_base, &mdModuleList.NumberOfModules, 
00563             sizeof(mdModuleList.NumberOfModules));
00564 
00565     return sz;
00566 }
00567 
00568 /* Calls cpuid with an eax of 'ax' and returns the 16 bytes in *p
00569  * We are compiled with -fPIC, so we can't clobber ebx.
00570  */
00571 static inline void do_x86cpuid(unsigned int ax, unsigned int *p)
00572 {
00573 #if defined(__GNUC__) && defined(__i386__)
00574     __asm__("pushl %%ebx\n\t"
00575             "cpuid\n\t"
00576             "movl %%ebx, %%esi\n\t"
00577             "popl %%ebx"
00578             : "=a" (p[0]), "=S" (p[1]), "=c" (p[2]), "=d" (p[3])
00579             :  "0" (ax));
00580 #endif
00581 }
00582 
00583 /* From xf86info havecpuid.c 1.11 */
00584 static inline int have_x86cpuid(void)
00585 {
00586 #if defined(__GNUC__) && defined(__i386__)
00587     unsigned int f1, f2;
00588     __asm__("pushfl\n\t"
00589             "pushfl\n\t"
00590             "popl %0\n\t"
00591             "movl %0,%1\n\t"
00592             "xorl %2,%0\n\t"
00593             "pushl %0\n\t"
00594             "popfl\n\t"
00595             "pushfl\n\t"
00596             "popl %0\n\t"
00597             "popfl"
00598             : "=&r" (f1), "=&r" (f2)
00599             : "ir" (0x00200000));
00600     return ((f1^f2) & 0x00200000) != 0;
00601 #else
00602     return 0;
00603 #endif
00604 }
00605 
00606 /******************************************************************
00607  *      dump_system_info
00608  *
00609  * Dumps into File the information about the system
00610  */
00611 static  unsigned        dump_system_info(struct dump_context* dc)
00612 {
00613     MINIDUMP_SYSTEM_INFO        mdSysInfo;
00614     SYSTEM_INFO                 sysInfo;
00615     OSVERSIONINFOW              osInfo;
00616     DWORD                       written;
00617     ULONG                       slen;
00618 
00619     GetSystemInfo(&sysInfo);
00620     osInfo.dwOSVersionInfoSize = sizeof(osInfo);
00621     GetVersionExW(&osInfo);
00622 
00623     mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture;
00624     mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel;
00625     mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision;
00626     mdSysInfo.u.s.NumberOfProcessors = sysInfo.dwNumberOfProcessors;
00627     mdSysInfo.u.s.ProductType = VER_NT_WORKSTATION; /* FIXME */
00628     mdSysInfo.MajorVersion = osInfo.dwMajorVersion;
00629     mdSysInfo.MinorVersion = osInfo.dwMinorVersion;
00630     mdSysInfo.BuildNumber = osInfo.dwBuildNumber;
00631     mdSysInfo.PlatformId = osInfo.dwPlatformId;
00632 
00633     mdSysInfo.CSDVersionRva = dc->rva + sizeof(mdSysInfo);
00634     mdSysInfo.u1.Reserved1 = 0;
00635     mdSysInfo.u1.s.SuiteMask = VER_SUITE_TERMINAL;
00636 
00637     if (have_x86cpuid())
00638     {
00639         unsigned        regs0[4], regs1[4];
00640 
00641         do_x86cpuid(0, regs0);
00642         mdSysInfo.Cpu.X86CpuInfo.VendorId[0] = regs0[1];
00643         mdSysInfo.Cpu.X86CpuInfo.VendorId[1] = regs0[2];
00644         mdSysInfo.Cpu.X86CpuInfo.VendorId[2] = regs0[3];
00645         do_x86cpuid(1, regs1);
00646         mdSysInfo.Cpu.X86CpuInfo.VersionInformation = regs1[0];
00647         mdSysInfo.Cpu.X86CpuInfo.FeatureInformation = regs1[3];
00648         mdSysInfo.Cpu.X86CpuInfo.AMDExtendedCpuFeatures = 0;
00649         if (regs0[1] == 0x68747541 /* "Auth" */ &&
00650             regs0[3] == 0x69746e65 /* "enti" */ &&
00651             regs0[2] == 0x444d4163 /* "cAMD" */)
00652         {
00653             do_x86cpuid(0x80000000, regs1);  /* get vendor cpuid level */
00654             if (regs1[0] >= 0x80000001)
00655             {
00656                 do_x86cpuid(0x80000001, regs1);  /* get vendor features */
00657                 mdSysInfo.Cpu.X86CpuInfo.AMDExtendedCpuFeatures = regs1[3];
00658             }
00659         }
00660     }
00661     else
00662     {
00663         unsigned        i;
00664         ULONG64         one = 1;
00665 
00666         mdSysInfo.Cpu.OtherCpuInfo.ProcessorFeatures[0] = 0;
00667         mdSysInfo.Cpu.OtherCpuInfo.ProcessorFeatures[1] = 0;
00668 
00669         for (i = 0; i < sizeof(mdSysInfo.Cpu.OtherCpuInfo.ProcessorFeatures[0]) * 8; i++)
00670             if (IsProcessorFeaturePresent(i))
00671                 mdSysInfo.Cpu.OtherCpuInfo.ProcessorFeatures[0] |= one << i;
00672     }
00673     append(dc, &mdSysInfo, sizeof(mdSysInfo));
00674 
00675     /* write the service pack version string after this stream.  It is referenced within the
00676        stream by its RVA in the file. */
00677     slen = lstrlenW(osInfo.szCSDVersion) * sizeof(WCHAR);
00678     WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
00679     WriteFile(dc->hFile, osInfo.szCSDVersion, slen, &written, NULL);
00680     dc->rva += sizeof(ULONG) + slen;
00681 
00682     return sizeof(mdSysInfo);
00683 }
00684 
00685 /******************************************************************
00686  *      dump_threads
00687  *
00688  * Dumps into File the information about running threads
00689  */
00690 static  unsigned        dump_threads(struct dump_context* dc,
00691                                      const MINIDUMP_EXCEPTION_INFORMATION* except)
00692 {
00693     MINIDUMP_THREAD             mdThd;
00694     MINIDUMP_THREAD_LIST        mdThdList;
00695     unsigned                    i, sz;
00696     RVA                         rva_base;
00697     DWORD                       flags_out;
00698     CONTEXT                     ctx;
00699 
00700     mdThdList.NumberOfThreads = 0;
00701 
00702     rva_base = dc->rva;
00703     dc->rva += sz = sizeof(mdThdList.NumberOfThreads) + dc->spi->dwThreadCount * sizeof(mdThd);
00704 
00705     for (i = 0; i < dc->spi->dwThreadCount; i++)
00706     {
00707         fetch_thread_info(dc, i, except, &mdThd, &ctx);
00708 
00709         flags_out = ThreadWriteThread | ThreadWriteStack | ThreadWriteContext |
00710             ThreadWriteInstructionWindow;
00711         if (dc->type & MiniDumpWithProcessThreadData)
00712             flags_out |= ThreadWriteThreadData;
00713         if (dc->type & MiniDumpWithThreadInfo)
00714             flags_out |= ThreadWriteThreadInfo;
00715 
00716         if (dc->cb)
00717         {
00718             MINIDUMP_CALLBACK_INPUT     cbin;
00719             MINIDUMP_CALLBACK_OUTPUT    cbout;
00720 
00721             cbin.ProcessId = dc->pid;
00722             cbin.ProcessHandle = dc->hProcess;
00723             cbin.CallbackType = ThreadCallback;
00724             cbin.u.Thread.ThreadId = HandleToUlong(dc->spi->ti[i].ClientId.UniqueThread);
00725             cbin.u.Thread.ThreadHandle = 0; /* FIXME */
00726             cbin.u.Thread.Context = ctx;
00727             cbin.u.Thread.SizeOfContext = sizeof(CONTEXT);
00728             cbin.u.Thread.StackBase = mdThd.Stack.StartOfMemoryRange;
00729             cbin.u.Thread.StackEnd = mdThd.Stack.StartOfMemoryRange +
00730                 mdThd.Stack.Memory.DataSize;
00731 
00732             cbout.u.ThreadWriteFlags = flags_out;
00733             if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
00734                 continue;
00735             flags_out &= cbout.u.ThreadWriteFlags;
00736         }
00737         if (flags_out & ThreadWriteThread)
00738         {
00739             if (ctx.ContextFlags && (flags_out & ThreadWriteContext))
00740             {
00741                 mdThd.ThreadContext.Rva = dc->rva;
00742                 mdThd.ThreadContext.DataSize = sizeof(CONTEXT);
00743                 append(dc, &ctx, sizeof(CONTEXT));
00744             }
00745             if (mdThd.Stack.Memory.DataSize && (flags_out & ThreadWriteStack))
00746             {
00747                 add_memory_block(dc, mdThd.Stack.StartOfMemoryRange,
00748                                  mdThd.Stack.Memory.DataSize,
00749                                  rva_base + sizeof(mdThdList.NumberOfThreads) +
00750                                      mdThdList.NumberOfThreads * sizeof(mdThd) +
00751                                      FIELD_OFFSET(MINIDUMP_THREAD, Stack.Memory.Rva));
00752             }
00753             writeat(dc, 
00754                     rva_base + sizeof(mdThdList.NumberOfThreads) +
00755                         mdThdList.NumberOfThreads * sizeof(mdThd),
00756                     &mdThd, sizeof(mdThd));
00757             mdThdList.NumberOfThreads++;
00758         }
00759         if (ctx.ContextFlags && (flags_out & ThreadWriteInstructionWindow))
00760         {
00761             /* FIXME: - Native dbghelp also dumps 0x80 bytes around EIP
00762              *        - also crop values across module boundaries, 
00763              *        - and don't make it i386 dependent 
00764              */
00765             /* add_memory_block(dc, ctx.Eip - 0x80, ctx.Eip + 0x80, 0); */
00766         }
00767     }
00768     writeat(dc, rva_base,
00769             &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads));
00770 
00771     return sz;
00772 }
00773 
00774 /******************************************************************
00775  *      dump_memory_info
00776  *
00777  * dumps information about the memory of the process (stack of the threads)
00778  */
00779 static unsigned         dump_memory_info(struct dump_context* dc)
00780 {
00781     MINIDUMP_MEMORY_LIST        mdMemList;
00782     MINIDUMP_MEMORY_DESCRIPTOR  mdMem;
00783     DWORD                       written;
00784     unsigned                    i, pos, len, sz;
00785     RVA                         rva_base;
00786     char                        tmp[1024];
00787 
00788     mdMemList.NumberOfMemoryRanges = dc->num_mem;
00789     append(dc, &mdMemList.NumberOfMemoryRanges,
00790            sizeof(mdMemList.NumberOfMemoryRanges));
00791     rva_base = dc->rva;
00792     sz = mdMemList.NumberOfMemoryRanges * sizeof(mdMem);
00793     dc->rva += sz;
00794     sz += sizeof(mdMemList.NumberOfMemoryRanges);
00795 
00796     for (i = 0; i < dc->num_mem; i++)
00797     {
00798         mdMem.StartOfMemoryRange = dc->mem[i].base;
00799         mdMem.Memory.Rva = dc->rva;
00800         mdMem.Memory.DataSize = dc->mem[i].size;
00801         SetFilePointer(dc->hFile, dc->rva, NULL, FILE_BEGIN);
00802         for (pos = 0; pos < dc->mem[i].size; pos += sizeof(tmp))
00803         {
00804             len = min(dc->mem[i].size - pos, sizeof(tmp));
00805             if (ReadProcessMemory(dc->hProcess, 
00806                                   (void*)(DWORD_PTR)(dc->mem[i].base + pos),
00807                                   tmp, len, NULL))
00808                 WriteFile(dc->hFile, tmp, len, &written, NULL);
00809         }
00810         dc->rva += mdMem.Memory.DataSize;
00811         writeat(dc, rva_base + i * sizeof(mdMem), &mdMem, sizeof(mdMem));
00812         if (dc->mem[i].rva)
00813         {
00814             writeat(dc, dc->mem[i].rva, &mdMem.Memory.Rva, sizeof(mdMem.Memory.Rva));
00815         }
00816     }
00817 
00818     return sz;
00819 }
00820 
00821 static unsigned         dump_misc_info(struct dump_context* dc)
00822 {
00823     MINIDUMP_MISC_INFO  mmi;
00824 
00825     mmi.SizeOfInfo = sizeof(mmi);
00826     mmi.Flags1 = MINIDUMP_MISC1_PROCESS_ID;
00827     mmi.ProcessId = dc->pid;
00828     /* FIXME: create/user/kernel time */
00829     mmi.ProcessCreateTime = 0;
00830     mmi.ProcessKernelTime = 0;
00831     mmi.ProcessUserTime = 0;
00832 
00833     append(dc, &mmi, sizeof(mmi));
00834     return sizeof(mmi);
00835 }
00836 
00837 /******************************************************************
00838  *      MiniDumpWriteDump (DEBUGHLP.@)
00839  *
00840  */
00841 BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
00842                               MINIDUMP_TYPE DumpType,
00843                               PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
00844                               PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
00845                               PMINIDUMP_CALLBACK_INFORMATION CallbackParam)
00846 {
00847     static const MINIDUMP_DIRECTORY emptyDir = {UnusedStream, {0, 0}};
00848     MINIDUMP_HEADER     mdHead;
00849     MINIDUMP_DIRECTORY  mdDir;
00850     DWORD               i, nStreams, idx_stream;
00851     struct dump_context dc;
00852 
00853     dc.hProcess = hProcess;
00854     dc.hFile = hFile;
00855     dc.pid = pid;
00856     dc.modules = NULL;
00857     dc.num_modules = 0;
00858     dc.alloc_modules = 0;
00859     dc.cb = CallbackParam;
00860     dc.type = DumpType;
00861     dc.mem = NULL;
00862     dc.num_mem = 0;
00863     dc.alloc_mem = 0;
00864     dc.rva = 0;
00865 
00866     if (!fetch_processes_info(&dc)) return FALSE;
00867     fetch_modules_info(&dc);
00868 
00869     /* 1) init */
00870     nStreams = 6 + (ExceptionParam ? 1 : 0) +
00871         (UserStreamParam ? UserStreamParam->UserStreamCount : 0);
00872 
00873     /* pad the directory size to a multiple of 4 for alignment purposes */
00874     nStreams = (nStreams + 3) & ~3;
00875 
00876     if (DumpType & MiniDumpWithDataSegs)
00877         FIXME("NIY MiniDumpWithDataSegs\n");
00878     if (DumpType & MiniDumpWithFullMemory)
00879         FIXME("NIY MiniDumpWithFullMemory\n");
00880     if (DumpType & MiniDumpWithHandleData)
00881         FIXME("NIY MiniDumpWithHandleData\n");
00882     if (DumpType & MiniDumpFilterMemory)
00883         FIXME("NIY MiniDumpFilterMemory\n");
00884     if (DumpType & MiniDumpScanMemory)
00885         FIXME("NIY MiniDumpScanMemory\n");
00886 
00887     /* 2) write header */
00888     mdHead.Signature = MINIDUMP_SIGNATURE;
00889     mdHead.Version = MINIDUMP_VERSION;  /* NOTE: native puts in an 'implementation specific' value in the high order word of this member */
00890     mdHead.NumberOfStreams = nStreams;
00891     mdHead.CheckSum = 0;                /* native sets a 0 checksum in its files */
00892     mdHead.StreamDirectoryRva = sizeof(mdHead);
00893     mdHead.u.TimeDateStamp = time(NULL);
00894     mdHead.Flags = DumpType;
00895     append(&dc, &mdHead, sizeof(mdHead));
00896 
00897     /* 3) write stream directories */
00898     dc.rva += nStreams * sizeof(mdDir);
00899     idx_stream = 0;
00900 
00901     /* 3.1) write data stream directories */
00902 
00903     /* must be first in minidump */
00904     mdDir.StreamType = SystemInfoStream;
00905     mdDir.Location.Rva = dc.rva;
00906     mdDir.Location.DataSize = dump_system_info(&dc);
00907     writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
00908             &mdDir, sizeof(mdDir));
00909 
00910     mdDir.StreamType = ThreadListStream;
00911     mdDir.Location.Rva = dc.rva;
00912     mdDir.Location.DataSize = dump_threads(&dc, ExceptionParam);
00913     writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), 
00914             &mdDir, sizeof(mdDir));
00915 
00916     mdDir.StreamType = ModuleListStream;
00917     mdDir.Location.Rva = dc.rva;
00918     mdDir.Location.DataSize = dump_modules(&dc, FALSE);
00919     writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
00920             &mdDir, sizeof(mdDir));
00921 
00922     mdDir.StreamType = 0xfff0; /* FIXME: this is part of MS reserved streams */
00923     mdDir.Location.Rva = dc.rva;
00924     mdDir.Location.DataSize = dump_modules(&dc, TRUE);
00925     writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
00926             &mdDir, sizeof(mdDir));
00927 
00928     mdDir.StreamType = MemoryListStream;
00929     mdDir.Location.Rva = dc.rva;
00930     mdDir.Location.DataSize = dump_memory_info(&dc);
00931     writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
00932             &mdDir, sizeof(mdDir));
00933 
00934     mdDir.StreamType = MiscInfoStream;
00935     mdDir.Location.Rva = dc.rva;
00936     mdDir.Location.DataSize = dump_misc_info(&dc);
00937     writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
00938             &mdDir, sizeof(mdDir));
00939 
00940     /* 3.2) write exception information (if any) */
00941     if (ExceptionParam)
00942     {
00943         mdDir.StreamType = ExceptionStream;
00944         mdDir.Location.Rva = dc.rva;
00945         mdDir.Location.DataSize = dump_exception_info(&dc, ExceptionParam);
00946         writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
00947                 &mdDir, sizeof(mdDir));
00948     }
00949 
00950     /* 3.3) write user defined streams (if any) */
00951     if (UserStreamParam)
00952     {
00953         for (i = 0; i < UserStreamParam->UserStreamCount; i++)
00954         {
00955             mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type;
00956             mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize;
00957             mdDir.Location.Rva = dc.rva;
00958             writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
00959                     &mdDir, sizeof(mdDir));
00960             append(&dc, UserStreamParam->UserStreamArray[i].Buffer, 
00961                    UserStreamParam->UserStreamArray[i].BufferSize);
00962         }
00963     }
00964 
00965     /* fill the remaining directory entries with 0's (unused stream types) */
00966     /* NOTE: this should always come last in the dump! */
00967     for (i = idx_stream; i < nStreams; i++)
00968         writeat(&dc, mdHead.StreamDirectoryRva + i * sizeof(emptyDir), &emptyDir, sizeof(emptyDir));
00969 
00970     HeapFree(GetProcessHeap(), 0, dc.pcs_buffer);
00971     HeapFree(GetProcessHeap(), 0, dc.mem);
00972     HeapFree(GetProcessHeap(), 0, dc.modules);
00973 
00974     return TRUE;
00975 }
00976 
00977 /******************************************************************
00978  *      MiniDumpReadDumpStream (DEBUGHLP.@)
00979  *
00980  *
00981  */
00982 BOOL WINAPI MiniDumpReadDumpStream(PVOID base, ULONG str_idx,
00983                                    PMINIDUMP_DIRECTORY* pdir,
00984                                    PVOID* stream, ULONG* size)
00985 {
00986     MINIDUMP_HEADER*    mdHead = base;
00987 
00988     if (mdHead->Signature == MINIDUMP_SIGNATURE)
00989     {
00990         MINIDUMP_DIRECTORY* dir;
00991         DWORD               i;
00992 
00993         dir = (MINIDUMP_DIRECTORY*)((char*)base + mdHead->StreamDirectoryRva);
00994         for (i = 0; i < mdHead->NumberOfStreams; i++, dir++)
00995         {
00996             if (dir->StreamType == str_idx)
00997             {
00998                 if (pdir) *pdir = dir;
00999                 if (stream) *stream = (char*)base + dir->Location.Rva;
01000                 if (size) *size = dir->Location.DataSize;
01001                 return TRUE;
01002             }
01003         }
01004     }
01005     SetLastError(ERROR_INVALID_PARAMETER);
01006     return FALSE;
01007 }

Generated on Sat May 26 2012 04:21:59 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.