Back to index

lightning-sunbird  0.9+nobinonly
nsStackFrameWin.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is nsStackFrameWin.h code, released
00017  * December 20, 2003.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 2003
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   Michael Judge, 20-December-2000
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "nscore.h"
00042 #include "windows.h"
00043 #include "stdio.h"
00044 #include "nsStackFrameWin.h"
00045 
00046 // Define these as static pointers so that we can load the DLL on the
00047 // fly (and not introduce a link-time dependency on it). Tip o' the
00048 // hat to Matt Pietrick for this idea. See:
00049 //
00050 //   http://msdn.microsoft.com/library/periodic/period97/F1/D3/S245C6.htm
00051 //
00052 
00053 
00054 PR_BEGIN_EXTERN_C
00055 
00056 SYMSETOPTIONSPROC _SymSetOptions;
00057 
00058 SYMINITIALIZEPROC _SymInitialize;
00059 
00060 SYMCLEANUPPROC _SymCleanup;
00061 
00062 STACKWALKPROC _StackWalk;
00063 #ifdef USING_WXP_VERSION
00064 STACKWALKPROC64 _StackWalk64;
00065 #else
00066 #define _StackWalk64 0
00067 #endif
00068 
00069 SYMFUNCTIONTABLEACCESSPROC _SymFunctionTableAccess;
00070 #ifdef USING_WXP_VERSION
00071 SYMFUNCTIONTABLEACCESSPROC64 _SymFunctionTableAccess64;
00072 #else
00073 #define _SymFunctionTableAccess64 0
00074 #endif
00075 
00076 SYMGETMODULEBASEPROC _SymGetModuleBase;
00077 #ifdef USING_WXP_VERSION
00078 SYMGETMODULEBASEPROC64 _SymGetModuleBase64;
00079 #else
00080 #define _SymGetModuleBase64 0
00081 #endif
00082 
00083 SYMGETSYMFROMADDRPROC _SymGetSymFromAddr;
00084 #ifdef USING_WXP_VERSION
00085 SYMFROMADDRPROC _SymFromAddr;
00086 #else
00087 #define _SymFromAddr 0
00088 #endif
00089 
00090 SYMLOADMODULE _SymLoadModule;
00091 #ifdef USING_WXP_VERSION
00092 SYMLOADMODULE64 _SymLoadModule64;
00093 #else
00094 #define _SymLoadModule64 0
00095 #endif
00096 
00097 SYMUNDNAME _SymUnDName;
00098 
00099 SYMGETMODULEINFO _SymGetModuleInfo;
00100 #ifdef USING_WXP_VERSION
00101 SYMGETMODULEINFO64 _SymGetModuleInfo64;
00102 #else
00103 #define _SymGetModuleInfo64 0
00104 #endif
00105 
00106 ENUMLOADEDMODULES _EnumerateLoadedModules;
00107 #ifdef USING_WXP_VERSION
00108 ENUMLOADEDMODULES64 _EnumerateLoadedModules64;
00109 #else
00110 #define _EnumerateLoadedModules64 0
00111 #endif
00112 
00113 SYMGETLINEFROMADDRPROC _SymGetLineFromAddr;
00114 #ifdef USING_WXP_VERSION
00115 SYMGETLINEFROMADDRPROC64 _SymGetLineFromAddr64;
00116 #else
00117 #define _SymGetLineFromAddr64 0
00118 #endif
00119 
00120 HANDLE hStackWalkMutex;
00121 
00122 PR_END_EXTERN_C
00123 
00124 // Routine to print an error message to standard error.
00125 // Will also print to an additional stream if one is supplied.
00126 void PrintError(char *prefix, FILE *out)
00127 {
00128     LPVOID lpMsgBuf;
00129     DWORD lastErr = GetLastError();
00130     FormatMessage(
00131       FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
00132       NULL,
00133       lastErr,
00134       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
00135       (LPTSTR) &lpMsgBuf,
00136       0,
00137       NULL
00138     );
00139     fprintf(stderr, "### ERROR: %s: %s", prefix, lpMsgBuf);
00140     if (out)
00141         fprintf(out, "### ERROR: %s: %s\n", prefix, lpMsgBuf);
00142     LocalFree( lpMsgBuf );
00143 }
00144 
00145 PRBool
00146 EnsureImageHlpInitialized()
00147 {
00148     static PRBool gInitialized = PR_FALSE;
00149 
00150     if (gInitialized)
00151         return gInitialized;
00152 
00153     // Create a mutex with no initial owner.
00154     hStackWalkMutex = CreateMutex(
00155       NULL,                       // default security attributes
00156       FALSE,                      // initially not owned
00157       NULL);                      // unnamed mutex
00158 
00159     if (hStackWalkMutex == NULL) {
00160         PrintError("CreateMutex", NULL);
00161         return PR_FALSE;
00162     }
00163 
00164     HMODULE module = ::LoadLibrary("DBGHELP.DLL");
00165     if (!module) {
00166         module = ::LoadLibrary("IMAGEHLP.DLL");
00167         if (!module) return PR_FALSE;
00168     }
00169 
00170     _SymSetOptions = (SYMSETOPTIONSPROC) ::GetProcAddress(module, "SymSetOptions");
00171     if (!_SymSetOptions) return PR_FALSE;
00172 
00173     _SymInitialize = (SYMINITIALIZEPROC) ::GetProcAddress(module, "SymInitialize");
00174     if (!_SymInitialize) return PR_FALSE;
00175 
00176     _SymCleanup = (SYMCLEANUPPROC)GetProcAddress(module, "SymCleanup");
00177     if (!_SymCleanup) return PR_FALSE;
00178 
00179 #ifdef USING_WXP_VERSION
00180     _StackWalk64 = (STACKWALKPROC64)GetProcAddress(module, "StackWalk64");
00181 #endif
00182     _StackWalk = (STACKWALKPROC)GetProcAddress(module, "StackWalk");
00183     if (!_StackWalk64  && !_StackWalk) return PR_FALSE;
00184 
00185 #ifdef USING_WXP_VERSION
00186     _SymFunctionTableAccess64 = (SYMFUNCTIONTABLEACCESSPROC64) GetProcAddress(module, "SymFunctionTableAccess64");
00187 #endif
00188     _SymFunctionTableAccess = (SYMFUNCTIONTABLEACCESSPROC) GetProcAddress(module, "SymFunctionTableAccess");
00189     if (!_SymFunctionTableAccess64 && !_SymFunctionTableAccess) return PR_FALSE;
00190 
00191 #ifdef USING_WXP_VERSION
00192     _SymGetModuleBase64 = (SYMGETMODULEBASEPROC64)GetProcAddress(module, "SymGetModuleBase64");
00193 #endif
00194     _SymGetModuleBase = (SYMGETMODULEBASEPROC)GetProcAddress(module, "SymGetModuleBase");
00195     if (!_SymGetModuleBase64 && !_SymGetModuleBase) return PR_FALSE;
00196 
00197     _SymGetSymFromAddr = (SYMGETSYMFROMADDRPROC)GetProcAddress(module, "SymGetSymFromAddr");
00198 #ifdef USING_WXP_VERSION
00199     _SymFromAddr = (SYMFROMADDRPROC)GetProcAddress(module, "SymFromAddr");
00200 #endif
00201     if (!_SymFromAddr && !_SymGetSymFromAddr) return PR_FALSE;
00202 
00203 #ifdef USING_WXP_VERSION
00204     _SymLoadModule64 = (SYMLOADMODULE64)GetProcAddress(module, "SymLoadModule64");
00205 #endif
00206     _SymLoadModule = (SYMLOADMODULE)GetProcAddress(module, "SymLoadModule");
00207     if (!_SymLoadModule64 && !_SymLoadModule) return PR_FALSE;
00208 
00209     _SymUnDName = (SYMUNDNAME)GetProcAddress(module, "SymUnDName");
00210     if (!_SymUnDName) return PR_FALSE;
00211 
00212 #ifdef USING_WXP_VERSION
00213     _SymGetModuleInfo64 = (SYMGETMODULEINFO64)GetProcAddress(module, "SymGetModuleInfo64");
00214 #endif
00215     _SymGetModuleInfo = (SYMGETMODULEINFO)GetProcAddress(module, "SymGetModuleInfo");
00216     if (!_SymGetModuleInfo64 && !_SymGetModuleInfo) return PR_FALSE;
00217 
00218 #ifdef USING_WXP_VERSION
00219     _EnumerateLoadedModules64 = (ENUMLOADEDMODULES64)GetProcAddress(module, "EnumerateLoadedModules64");
00220 #endif
00221     _EnumerateLoadedModules = (ENUMLOADEDMODULES)GetProcAddress(module, "EnumerateLoadedModules");
00222     if (!_EnumerateLoadedModules64 && !_EnumerateLoadedModules) return PR_FALSE;
00223 
00224 #ifdef USING_WXP_VERSION
00225     _SymGetLineFromAddr64 = (SYMGETLINEFROMADDRPROC64)GetProcAddress(module, "SymGetLineFromAddr64");
00226 #endif
00227     _SymGetLineFromAddr = (SYMGETLINEFROMADDRPROC)GetProcAddress(module, "SymGetLineFromAddr");
00228     if (!_SymGetLineFromAddr64 && !_SymGetLineFromAddr) return PR_FALSE;
00229 
00230     return gInitialized = PR_TRUE;
00231 }
00232 
00233 
00234 static BOOL CALLBACK callbackEspecial(
00235   LPSTR aModuleName,
00236   DWORD aModuleBase,
00237   ULONG aModuleSize,
00238   PVOID aUserContext)
00239 {
00240     BOOL retval = TRUE;
00241     DWORD addr = *(DWORD*)aUserContext;
00242 
00243     /*
00244      * You'll want to control this if we are running on an
00245      *  architecture where the addresses go the other direction.
00246      * Not sure this is even a realistic consideration.
00247      */
00248     const BOOL addressIncreases = TRUE;
00249 
00250     /*
00251      * If it falls inside the known range, load the symbols.
00252      */
00253     if (addressIncreases
00254        ? (addr >= aModuleBase && addr <= (aModuleBase + aModuleSize))
00255        : (addr <= aModuleBase && addr >= (aModuleBase - aModuleSize))
00256         ) {
00257         retval = _SymLoadModule(GetCurrentProcess(), NULL, aModuleName, NULL, aModuleBase, aModuleSize);
00258     }
00259 
00260     return retval;
00261 }
00262 
00263 static BOOL CALLBACK callbackEspecial64(
00264   PTSTR aModuleName,
00265   DWORD64 aModuleBase,
00266   ULONG aModuleSize,
00267   PVOID aUserContext)
00268 {
00269 #ifdef USING_WXP_VERSION
00270     BOOL retval = TRUE;
00271     DWORD64 addr = *(DWORD64*)aUserContext;
00272 
00273     /*
00274      * You'll want to control this if we are running on an
00275      *  architecture where the addresses go the other direction.
00276      * Not sure this is even a realistic consideration.
00277      */
00278     const BOOL addressIncreases = TRUE;
00279 
00280     /*
00281      * If it falls in side the known range, load the symbols.
00282      */
00283     if (addressIncreases
00284        ? (addr >= aModuleBase && addr <= (aModuleBase + aModuleSize))
00285        : (addr <= aModuleBase && addr >= (aModuleBase - aModuleSize))
00286         ) {
00287         retval = _SymLoadModule64(GetCurrentProcess(), NULL, aModuleName, NULL, aModuleBase, aModuleSize);
00288     }
00289 
00290     return retval;
00291 #else
00292     return FALSE;
00293 #endif
00294 }
00295 
00296 /*
00297  * SymGetModuleInfoEspecial
00298  *
00299  * Attempt to determine the module information.
00300  * Bug 112196 says this DLL may not have been loaded at the time
00301  *  SymInitialize was called, and thus the module information
00302  *  and symbol information is not available.
00303  * This code rectifies that problem.
00304  */
00305 BOOL SymGetModuleInfoEspecial(HANDLE aProcess, DWORD aAddr, PIMAGEHLP_MODULE aModuleInfo, PIMAGEHLP_LINE aLineInfo)
00306 {
00307     BOOL retval = FALSE;
00308 
00309     /*
00310      * Init the vars if we have em.
00311      */
00312     aModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE);
00313     if (nsnull != aLineInfo) {
00314       aLineInfo->SizeOfStruct = sizeof(IMAGEHLP_LINE);
00315     }
00316 
00317     /*
00318      * Give it a go.
00319      * It may already be loaded.
00320      */
00321     retval = _SymGetModuleInfo(aProcess, aAddr, aModuleInfo);
00322 
00323     if (FALSE == retval) {
00324         BOOL enumRes = FALSE;
00325 
00326         /*
00327          * Not loaded, here's the magic.
00328          * Go through all the modules.
00329          */
00330         enumRes = _EnumerateLoadedModules(aProcess, callbackEspecial, (PVOID)&aAddr);
00331         if (FALSE != enumRes)
00332         {
00333             /*
00334              * One final go.
00335              * If it fails, then well, we have other problems.
00336              */
00337             retval = _SymGetModuleInfo(aProcess, aAddr, aModuleInfo);
00338         }
00339     }
00340 
00341     /*
00342      * If we got module info, we may attempt line info as well.
00343      * We will not report failure if this does not work.
00344      */
00345     if (FALSE != retval && nsnull != aLineInfo && nsnull != _SymGetLineFromAddr) {
00346         DWORD displacement = 0;
00347         BOOL lineRes = FALSE;
00348         lineRes = _SymGetLineFromAddr(aProcess, aAddr, &displacement, aLineInfo);
00349     }
00350 
00351     return retval;
00352 }
00353 
00354 #ifdef USING_WXP_VERSION
00355 BOOL SymGetModuleInfoEspecial64(HANDLE aProcess, DWORD64 aAddr, PIMAGEHLP_MODULE64 aModuleInfo, PIMAGEHLP_LINE64 aLineInfo)
00356 {
00357     BOOL retval = FALSE;
00358 
00359     /*
00360      * Init the vars if we have em.
00361      */
00362     aModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
00363     if (nsnull != aLineInfo) {
00364         aLineInfo->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
00365     }
00366 
00367     /*
00368      * Give it a go.
00369      * It may already be loaded.
00370      */
00371     retval = _SymGetModuleInfo64(aProcess, aAddr, aModuleInfo);
00372 
00373     if (FALSE == retval) {
00374         BOOL enumRes = FALSE;
00375 
00376         /*
00377          * Not loaded, here's the magic.
00378          * Go through all the modules.
00379          */
00380         enumRes = _EnumerateLoadedModules64(aProcess, callbackEspecial64, (PVOID)&aAddr);
00381         if (FALSE != enumRes)
00382         {
00383             /*
00384              * One final go.
00385              * If it fails, then well, we have other problems.
00386              */
00387             retval = _SymGetModuleInfo64(aProcess, aAddr, aModuleInfo);
00388         }
00389     }
00390 
00391     /*
00392      * If we got module info, we may attempt line info as well.
00393      * We will not report failure if this does not work.
00394      */
00395     if (FALSE != retval && nsnull != aLineInfo && nsnull != _SymGetLineFromAddr64) {
00396         DWORD displacement = 0;
00397         BOOL lineRes = FALSE;
00398         lineRes = _SymGetLineFromAddr64(aProcess, aAddr, &displacement, aLineInfo);
00399     }
00400 
00401     return retval;
00402 }
00403 #endif
00404 
00405 HANDLE
00406 GetCurrentPIDorHandle()
00407 {
00408     if (_SymGetModuleBase64)
00409         return GetCurrentProcess();  // winxp and friends use process handle
00410 
00411     return (HANDLE) GetCurrentProcessId(); // winme win98 win95 etc use process identifier
00412 }
00413 
00414 PRBool
00415 EnsureSymInitialized()
00416 {
00417     PRBool retStat;
00418 
00419     if (!EnsureImageHlpInitialized())
00420         return PR_FALSE;
00421 
00422     _SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
00423     retStat = _SymInitialize(GetCurrentPIDorHandle(), NULL, TRUE);
00424     if (!retStat)
00425         PrintError("SymInitialize", NULL);
00426     return retStat;
00427 }
00428 
00429 
00438 void
00439 DumpStackToFile(FILE* aStream)
00440 {
00441     HANDLE myProcess = ::GetCurrentProcess();
00442     HANDLE myThread, walkerThread;
00443     DWORD walkerReturn;
00444     struct DumpStackToFileData data;
00445 
00446     if (!EnsureSymInitialized())
00447         return;
00448 
00449     // Have to duplicate handle to get a real handle.
00450     ::DuplicateHandle(
00451       ::GetCurrentProcess(),
00452       ::GetCurrentThread(),
00453       ::GetCurrentProcess(),
00454       &myThread,
00455       THREAD_ALL_ACCESS, FALSE, 0
00456     );
00457 
00458     data.stream = aStream;
00459     data.thread = myThread;
00460     data.process = myProcess;
00461     walkerThread = ::CreateThread( NULL, 0, DumpStackToFileThread, (LPVOID) &data, 0, NULL ) ;
00462     if (walkerThread) {
00463         walkerReturn = ::WaitForSingleObject(walkerThread, 2000); // no timeout is never a good idea
00464         CloseHandle(myThread) ;
00465         if (walkerReturn != WAIT_OBJECT_0) {
00466             PrintError("ThreadWait", aStream);
00467         }
00468     }
00469     else {
00470         PrintError("ThreadCreate", aStream);
00471     }
00472     return;
00473 }
00474 
00475 DWORD WINAPI
00476 DumpStackToFileThread(LPVOID lpdata)
00477 {
00478     struct DumpStackToFileData *data = (DumpStackToFileData *)lpdata;
00479     DWORD ret ;
00480 
00481     // Suspend the calling thread, dump his stack, and then resume him.
00482     // He's currently waiting for us to finish so now should be a good time.
00483     ret = ::SuspendThread( data->thread );
00484     if (ret == -1) {
00485         PrintError("ThreadSuspend", data->stream);
00486     }
00487     else {
00488         if (_StackWalk64)
00489             DumpStackToFileMain64(data);
00490         else
00491             DumpStackToFileMain(data);
00492         ret = ::ResumeThread(data->thread);
00493         if (ret == -1) {
00494             PrintError("ThreadResume", data->stream);
00495         }
00496     }
00497 
00498     return 0;
00499 }
00500 
00501 void
00502 DumpStackToFileMain64(struct DumpStackToFileData* data)
00503 {
00504 #ifdef USING_WXP_VERSION
00505     // Get the context information for the thread. That way we will
00506     // know where our sp, fp, pc, etc. are and can fill in the
00507     // STACKFRAME64 with the initial values.
00508     CONTEXT context;
00509     HANDLE myProcess = data->process;
00510     HANDLE myThread = data->thread;
00511     FILE* aStream = data->stream;
00512     DWORD64 addr;
00513     STACKFRAME64 frame64;
00514     int skip = 6; // skip our own stack walking frames
00515     BOOL ok;
00516 
00517     // Get a context for the specified thread.
00518     memset(&context, 0, sizeof(CONTEXT));
00519     context.ContextFlags = CONTEXT_FULL;
00520     if (!GetThreadContext(myThread, &context)) {
00521         PrintError("GetThreadContext", aStream);
00522         return;
00523     }
00524 
00525     // Setup initial stack frame to walk from
00526     memset(&frame64, 0, sizeof(frame64));
00527 #ifdef _M_IX86
00528     frame64.AddrPC.Offset    = context.Eip;
00529     frame64.AddrStack.Offset = context.Esp;
00530     frame64.AddrFrame.Offset = context.Ebp;
00531 #elif defined _M_AMD64
00532     frame64.AddrPC.Offset    = context.Rip;
00533     frame64.AddrStack.Offset = context.Rsp;
00534     frame64.AddrFrame.Offset = context.Rbp;
00535 #elif defined _M_IA64
00536     frame64.AddrPC.Offset    = context.StIIP;
00537     frame64.AddrStack.Offset = context.SP;
00538     frame64.AddrFrame.Offset = context.RsBSP;
00539 #else
00540     fprintf(aStream, "Unknown platform. No stack walking.");
00541     return;
00542 #endif
00543     frame64.AddrPC.Mode      = AddrModeFlat;
00544     frame64.AddrStack.Mode   = AddrModeFlat;
00545     frame64.AddrFrame.Mode   = AddrModeFlat;
00546     frame64.AddrReturn.Mode  = AddrModeFlat;
00547 
00548     // Now walk the stack and map the pc's to symbol names
00549     while (1) {
00550 
00551         ok = 0;
00552 
00553         // stackwalk is not threadsafe, so grab the lock.
00554         DWORD dwWaitResult;
00555         dwWaitResult = WaitForSingleObject(hStackWalkMutex, INFINITE);
00556         if (dwWaitResult == WAIT_OBJECT_0) {
00557 
00558             ok = _StackWalk64(
00559 #ifdef _M_AMD64
00560               IMAGE_FILE_MACHINE_AMD64,
00561 #elif defined _M_IA64
00562               IMAGE_FILE_MACHINE_IA64,
00563 #elif defined _M_IX86
00564               IMAGE_FILE_MACHINE_I386,
00565 #else
00566               0,
00567 #endif
00568               myProcess,
00569               myThread,
00570               &frame64,
00571               &context,
00572               NULL,
00573               _SymFunctionTableAccess64, // function table access routine
00574               _SymGetModuleBase64,       // module base routine
00575               0
00576             );
00577 
00578             if (ok)
00579                 addr = frame64.AddrPC.Offset;
00580             else
00581                 PrintError("WalkStack64", aStream);
00582 
00583             if (!ok || (addr == 0)) {
00584                 ReleaseMutex(hStackWalkMutex);  // release our lock
00585                 break;
00586             }
00587 
00588             if (skip-- > 0) {
00589                 ReleaseMutex(hStackWalkMutex);  // release our lock
00590                 continue;
00591             }
00592 
00593             //
00594             // Attempt to load module info before we attempt to reolve the symbol.
00595             // This just makes sure we get good info if available.
00596             //
00597 
00598             IMAGEHLP_MODULE64 modInfo;
00599             modInfo.SizeOfStruct = sizeof(modInfo);
00600             BOOL modInfoRes;
00601             modInfoRes = SymGetModuleInfoEspecial64(myProcess, addr, &modInfo, nsnull);
00602 
00603             ULONG64 buffer[(sizeof(SYMBOL_INFO) +
00604               MAX_SYM_NAME*sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
00605             PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
00606             pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
00607             pSymbol->MaxNameLen = MAX_SYM_NAME;
00608 
00609             DWORD64 displacement;
00610             ok = _SymFromAddr && _SymFromAddr(myProcess, addr, &displacement, pSymbol);
00611 
00612             // All done with debug calls so release our lock.
00613             ReleaseMutex(hStackWalkMutex);
00614 
00615             if (ok)
00616                 fprintf(aStream, "%s!%s+0x%016X\n", modInfo.ImageName, pSymbol->Name, displacement);
00617             else
00618                 fprintf(aStream, "0x%016X\n", addr);
00619 
00620             // Stop walking when we get to kernel32.dll.
00621             if (strcmp(modInfo.ImageName, "kernel32.dll") == 0)
00622                 break;
00623         }
00624         else {
00625             PrintError("LockError64", aStream);
00626         } 
00627     }
00628     return;
00629 #endif
00630 }
00631 
00632 
00633 void
00634 DumpStackToFileMain(struct DumpStackToFileData* data)
00635 {
00636     // Get the context information for the thread. That way we will
00637     // know where our sp, fp, pc, etc. are and can fill in the
00638     // STACKFRAME with the initial values.
00639     CONTEXT context;
00640     HANDLE myProcess = data->process;
00641     HANDLE myThread = data->thread;
00642     FILE* aStream = data->stream;
00643     DWORD addr;
00644     STACKFRAME frame;
00645     int skip = 2;  // skip our own stack walking frames
00646     BOOL ok;
00647 
00648     // Get a context for the specified thread.
00649     memset(&context, 0, sizeof(CONTEXT));
00650     context.ContextFlags = CONTEXT_FULL;
00651     if (!GetThreadContext(myThread, &context)) {
00652         PrintError("GetThreadContext", aStream);
00653         return;
00654     }
00655 
00656     // Setup initial stack frame to walk from
00657 #if defined _M_IX86
00658     memset(&frame, 0, sizeof(frame));
00659     frame.AddrPC.Offset    = context.Eip;
00660     frame.AddrPC.Mode      = AddrModeFlat;
00661     frame.AddrStack.Offset = context.Esp;
00662     frame.AddrStack.Mode   = AddrModeFlat;
00663     frame.AddrFrame.Offset = context.Ebp;
00664     frame.AddrFrame.Mode   = AddrModeFlat;
00665 #else
00666     fprintf(aStream, "Unknown platform. No stack walking.");
00667     return;
00668 #endif
00669 
00670     // Now walk the stack and map the pc's to symbol names
00671     while (1) {
00672 
00673         ok = 0;
00674 
00675         // debug routines are not threadsafe, so grab the lock.
00676         DWORD dwWaitResult;
00677         dwWaitResult = WaitForSingleObject(hStackWalkMutex, INFINITE);
00678         if (dwWaitResult == WAIT_OBJECT_0) {
00679 
00680             ok = _StackWalk(
00681                 IMAGE_FILE_MACHINE_I386,
00682                 myProcess,
00683                 myThread,
00684                 &frame,
00685                 &context,
00686                 0,                        // read process memory routine
00687                 _SymFunctionTableAccess,  // function table access routine
00688                 _SymGetModuleBase,        // module base routine
00689                 0                         // translate address routine
00690               );
00691 
00692             if (ok)
00693                 addr = frame.AddrPC.Offset;
00694             else
00695                 PrintError("WalkStack", aStream);
00696 
00697             if (!ok || (addr == 0)) {
00698                 ReleaseMutex(hStackWalkMutex);  // release our lock
00699                 break;
00700             }
00701 
00702             if (skip-- > 0) {
00703                 ReleaseMutex(hStackWalkMutex);  // release the lock
00704                 continue;
00705             }
00706 
00707             //
00708             // Attempt to load module info before we attempt to resolve the symbol.
00709             // This just makes sure we get good info if available.
00710             //
00711 
00712             IMAGEHLP_MODULE modInfo;
00713             modInfo.SizeOfStruct = sizeof(modInfo);
00714             BOOL modInfoRes;
00715             modInfoRes = SymGetModuleInfoEspecial(myProcess, addr, &modInfo, nsnull);
00716 
00717 #ifdef USING_WXP_VERSION
00718             ULONG64 buffer[(sizeof(SYMBOL_INFO) +
00719               MAX_SYM_NAME*sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)];
00720             PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
00721             pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
00722             pSymbol->MaxNameLen = MAX_SYM_NAME;
00723 
00724             DWORD64 displacement;
00725 
00726             ok = _SymFromAddr && _SymFromAddr(myProcess, addr, &displacement, pSymbol);
00727 #else
00728             char buf[sizeof(IMAGEHLP_SYMBOL) + 512];
00729             PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL) buf;
00730             pSymbol->SizeOfStruct = sizeof(buf);
00731             pSymbol->MaxNameLength = 512;
00732 
00733             DWORD displacement;
00734 
00735             ok = _SymGetSymFromAddr(myProcess,
00736                         frame.AddrPC.Offset,
00737                         &displacement,
00738                         pSymbol);
00739 #endif
00740 
00741             // All done with debug calls so release our lock.
00742             ReleaseMutex(hStackWalkMutex);
00743 
00744             if (ok)
00745                 fprintf(aStream, "%s!%s+0x%08X\n", modInfo.ImageName, pSymbol->Name, displacement);
00746             else
00747                 fprintf(aStream, "0x%08X\n", (DWORD) addr);
00748 
00749             // Stop walking when we get to kernel32.dll.
00750             if (strcmp(modInfo.ImageName, "kernel32.dll") == 0)
00751                 break;
00752 
00753         }
00754         else {
00755             PrintError("LockError", aStream);
00756         }
00757         
00758     }
00759 
00760     return;
00761 
00762 }