PageRenderTime 36ms CodeModel.GetById 22ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llstacktrace.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 136 lines | 88 code | 16 blank | 32 comment | 6 complexity | 7b50239aa507912636d797b0fc1e5ffa MD5 | raw file
  1/** 
  2 * @file llstacktrace.cpp
  3 * @brief stack tracing functionality
  4 *
  5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28#include "llstacktrace.h"
 29
 30#ifdef LL_WINDOWS
 31
 32#include <iostream>
 33#include <sstream>
 34
 35#include "windows.h"
 36#include "Dbghelp.h"
 37
 38typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
 39    IN ULONG frames_to_skip,
 40    IN ULONG frames_to_capture,
 41    OUT PVOID *backtrace,
 42    OUT PULONG backtrace_hash);
 43
 44static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
 45   (RtlCaptureStackBackTrace_Function*)
 46   GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
 47
 48bool ll_get_stack_trace(std::vector<std::string>& lines)
 49{
 50	const S32 MAX_STACK_DEPTH = 32;
 51	const S32 STRING_NAME_LENGTH = 200;
 52	const S32 FRAME_SKIP = 2;
 53	static BOOL symbolsLoaded = false;
 54	static BOOL firstCall = true;
 55
 56	HANDLE hProc = GetCurrentProcess();
 57
 58	// load the symbols if they're not loaded
 59	if(!symbolsLoaded && firstCall)
 60	{
 61		symbolsLoaded = SymInitialize(hProc, NULL, true);
 62		firstCall = false;
 63	}
 64
 65	// if loaded, get the call stack
 66	if(symbolsLoaded)
 67	{
 68		// create the frames to hold the addresses
 69		void* frames[MAX_STACK_DEPTH];
 70		memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH);
 71		S32 depth = 0;
 72
 73		// get the addresses
 74		depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL);
 75
 76		IMAGEHLP_LINE64 line;
 77		memset(&line, 0, sizeof(IMAGEHLP_LINE64));
 78		line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
 79
 80		// create something to hold address info
 81		PIMAGEHLP_SYMBOL64 pSym;
 82		pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
 83		memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
 84		pSym->MaxNameLength = STRING_NAME_LENGTH;
 85		pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
 86
 87		// get address info for each address frame
 88		// and store
 89		for(S32 i=0; i < depth; i++)
 90		{
 91			std::stringstream stack_line;
 92			BOOL ret;
 93
 94			DWORD64 addr = (DWORD64)frames[i];
 95			ret = SymGetSymFromAddr64(hProc, addr, 0, pSym);
 96			if(ret)
 97			{
 98				stack_line << pSym->Name << " ";
 99			}
100
101			DWORD dummy;
102			ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line);
103			if(ret)
104			{
105				std::string file_name = line.FileName;
106				std::string::size_type index = file_name.rfind("\\");
107				stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; 
108			}
109
110			lines.push_back(stack_line.str());
111		}
112		
113		free(pSym);
114
115		// TODO: figure out a way to cleanup symbol loading
116		// Not hugely necessary, however.
117		//SymCleanup(hProc);
118		return true;
119	}
120	else
121	{
122		lines.push_back("Stack Trace Failed.  PDB symbol info not loaded");
123	}
124
125	return false;
126}
127
128#else
129
130bool ll_get_stack_trace(std::vector<std::string>& lines)
131{
132	return false;
133}
134
135#endif
136