You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
500 lines
20 KiB
500 lines
20 KiB
# DExTer : Debugging Experience Tester
|
|
# ~~~~~~ ~ ~~ ~ ~~
|
|
#
|
|
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
# See https://llvm.org/LICENSE.txt for license information.
|
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
from collections import namedtuple
|
|
from ctypes import *
|
|
from enum import *
|
|
from functools import reduce, partial
|
|
|
|
from .symgroup import SymbolGroup, IDebugSymbolGroup2
|
|
from .utils import *
|
|
|
|
class SymbolOptionFlags(IntFlag):
|
|
SYMOPT_CASE_INSENSITIVE = 0x00000001
|
|
SYMOPT_UNDNAME = 0x00000002
|
|
SYMOPT_DEFERRED_LOADS = 0x00000004
|
|
SYMOPT_NO_CPP = 0x00000008
|
|
SYMOPT_LOAD_LINES = 0x00000010
|
|
SYMOPT_OMAP_FIND_NEAREST = 0x00000020
|
|
SYMOPT_LOAD_ANYTHING = 0x00000040
|
|
SYMOPT_IGNORE_CVREC = 0x00000080
|
|
SYMOPT_NO_UNQUALIFIED_LOADS = 0x00000100
|
|
SYMOPT_FAIL_CRITICAL_ERRORS = 0x00000200
|
|
SYMOPT_EXACT_SYMBOLS = 0x00000400
|
|
SYMOPT_ALLOW_ABSOLUTE_SYMBOLS = 0x00000800
|
|
SYMOPT_IGNORE_NT_SYMPATH = 0x00001000
|
|
SYMOPT_INCLUDE_32BIT_MODULES = 0x00002000
|
|
SYMOPT_PUBLICS_ONLY = 0x00004000
|
|
SYMOPT_NO_PUBLICS = 0x00008000
|
|
SYMOPT_AUTO_PUBLICS = 0x00010000
|
|
SYMOPT_NO_IMAGE_SEARCH = 0x00020000
|
|
SYMOPT_SECURE = 0x00040000
|
|
SYMOPT_NO_PROMPTS = 0x00080000
|
|
SYMOPT_DEBUG = 0x80000000
|
|
|
|
class ScopeGroupFlags(IntFlag):
|
|
DEBUG_SCOPE_GROUP_ARGUMENTS = 0x00000001
|
|
DEBUG_SCOPE_GROUP_LOCALS = 0x00000002
|
|
DEBUG_SCOPE_GROUP_ALL = 0x00000003
|
|
DEBUG_SCOPE_GROUP_BY_DATAMODEL = 0x00000004
|
|
|
|
class DebugModuleNames(IntEnum):
|
|
DEBUG_MODNAME_IMAGE = 0x00000000
|
|
DEBUG_MODNAME_MODULE = 0x00000001
|
|
DEBUG_MODNAME_LOADED_IMAGE = 0x00000002
|
|
DEBUG_MODNAME_SYMBOL_FILE = 0x00000003
|
|
DEBUG_MODNAME_MAPPED_IMAGE = 0x00000004
|
|
|
|
class DebugModuleFlags(IntFlag):
|
|
DEBUG_MODULE_LOADED = 0x00000000
|
|
DEBUG_MODULE_UNLOADED = 0x00000001
|
|
DEBUG_MODULE_USER_MODE = 0x00000002
|
|
DEBUG_MODULE_EXE_MODULE = 0x00000004
|
|
DEBUG_MODULE_EXPLICIT = 0x00000008
|
|
DEBUG_MODULE_SECONDARY = 0x00000010
|
|
DEBUG_MODULE_SYNTHETIC = 0x00000020
|
|
DEBUG_MODULE_SYM_BAD_CHECKSUM = 0x00010000
|
|
|
|
class DEBUG_MODULE_PARAMETERS(Structure):
|
|
_fields_ = [
|
|
("Base", c_ulonglong),
|
|
("Size", c_ulong),
|
|
("TimeDateStamp", c_ulong),
|
|
("Checksum", c_ulong),
|
|
("Flags", c_ulong),
|
|
("SymbolType", c_ulong),
|
|
("ImageNameSize", c_ulong),
|
|
("ModuleNameSize", c_ulong),
|
|
("LoadedImageNameSize", c_ulong),
|
|
("SymbolFileNameSize", c_ulong),
|
|
("MappedImageNameSize", c_ulong),
|
|
("Reserved", c_ulonglong * 2)
|
|
]
|
|
PDEBUG_MODULE_PARAMETERS = POINTER(DEBUG_MODULE_PARAMETERS)
|
|
|
|
class DEBUG_MODULE_AND_ID(Structure):
|
|
_fields_ = [
|
|
("ModuleBase", c_ulonglong),
|
|
("Id", c_ulonglong)
|
|
]
|
|
PDEBUG_MODULE_AND_ID = POINTER(DEBUG_MODULE_AND_ID)
|
|
|
|
class DEBUG_SYMBOL_ENTRY(Structure):
|
|
_fields_ = [
|
|
("ModuleBase", c_ulonglong),
|
|
("Offset", c_ulonglong),
|
|
("Id", c_ulonglong),
|
|
("Arg64", c_ulonglong),
|
|
("Size", c_ulong),
|
|
("Flags", c_ulong),
|
|
("TypeId", c_ulong),
|
|
("NameSize", c_ulong),
|
|
("Token", c_ulong),
|
|
("Tag", c_ulong),
|
|
("Arg32", c_ulong),
|
|
("Reserved", c_ulong)
|
|
]
|
|
PDEBUG_SYMBOL_ENTRY = POINTER(DEBUG_SYMBOL_ENTRY)
|
|
|
|
# UUID for DebugSymbols5 interface.
|
|
DebugSymbols5IID = IID(0xc65fa83e, 0x1e69, 0x475e, IID_Data4_Type(0x8e, 0x0e, 0xb5, 0xd7, 0x9e, 0x9c, 0xc1, 0x7e))
|
|
|
|
class IDebugSymbols5(Structure):
|
|
pass
|
|
|
|
class IDebugSymbols5Vtbl(Structure):
|
|
wrp = partial(WINFUNCTYPE, c_long, POINTER(IDebugSymbols5))
|
|
ids_getsymboloptions = wrp(c_ulong_p)
|
|
ids_setsymboloptions = wrp(c_ulong)
|
|
ids_getmoduleparameters = wrp(c_ulong, c_ulong64_p, c_ulong, PDEBUG_MODULE_PARAMETERS)
|
|
ids_getmodulenamestring = wrp(c_ulong, c_ulong, c_ulonglong, c_char_p, c_ulong, c_ulong_p)
|
|
ids_getoffsetbyname = wrp(c_char_p, c_ulong64_p)
|
|
ids_getlinebyoffset = wrp(c_ulonglong, c_ulong_p, c_char_p, c_ulong, c_ulong_p, c_ulong64_p)
|
|
ids_getsymbolentriesbyname = wrp(c_char_p, c_ulong, PDEBUG_MODULE_AND_ID, c_ulong, c_ulong_p)
|
|
ids_getsymbolentrystring = wrp(PDEBUG_MODULE_AND_ID, c_ulong, c_char_p, c_ulong, c_ulong_p)
|
|
ids_getsymbolentryinformation = wrp(PDEBUG_MODULE_AND_ID, PDEBUG_SYMBOL_ENTRY)
|
|
ids_getcurrentscopeframeindex = wrp(c_ulong_p)
|
|
ids_getnearnamebyoffset = wrp(c_ulonglong, c_long, c_char_p, c_ulong, c_ulong_p, c_ulong64_p)
|
|
ids_setscopeframebyindex = wrp(c_ulong)
|
|
ids_getscopesymbolgroup2 = wrp(c_ulong, POINTER(IDebugSymbolGroup2), POINTER(POINTER(IDebugSymbolGroup2)))
|
|
ids_getnamebyinlinecontext = wrp(c_ulonglong, c_ulong, c_char_p, c_ulong, c_ulong_p, c_ulong64_p)
|
|
ids_getlinebyinlinecontext = wrp(c_ulonglong, c_ulong, c_ulong_p, c_char_p, c_ulong, c_ulong_p, c_ulong64_p)
|
|
_fields_ = [
|
|
("QueryInterface", c_void_p),
|
|
("AddRef", c_void_p),
|
|
("Release", c_void_p),
|
|
("GetSymbolOptions", ids_getsymboloptions),
|
|
("AddSymbolOptions", c_void_p),
|
|
("RemoveSymbolOptions", c_void_p),
|
|
("SetSymbolOptions", ids_setsymboloptions),
|
|
("GetNameByOffset", c_void_p),
|
|
("GetOffsetByName", ids_getoffsetbyname),
|
|
("GetNearNameByOffset", ids_getnearnamebyoffset),
|
|
("GetLineByOffset", ids_getlinebyoffset),
|
|
("GetOffsetByLine", c_void_p),
|
|
("GetNumberModules", c_void_p),
|
|
("GetModuleByIndex", c_void_p),
|
|
("GetModuleByModuleName", c_void_p),
|
|
("GetModuleByOffset", c_void_p),
|
|
("GetModuleNames", c_void_p),
|
|
("GetModuleParameters", ids_getmoduleparameters),
|
|
("GetSymbolModule", c_void_p),
|
|
("GetTypeName", c_void_p),
|
|
("GetTypeId", c_void_p),
|
|
("GetTypeSize", c_void_p),
|
|
("GetFieldOffset", c_void_p),
|
|
("GetSymbolTypeId", c_void_p),
|
|
("GetOffsetTypeId", c_void_p),
|
|
("ReadTypedDataVirtual", c_void_p),
|
|
("WriteTypedDataVirtual", c_void_p),
|
|
("OutputTypedDataVirtual", c_void_p),
|
|
("ReadTypedDataPhysical", c_void_p),
|
|
("WriteTypedDataPhysical", c_void_p),
|
|
("OutputTypedDataPhysical", c_void_p),
|
|
("GetScope", c_void_p),
|
|
("SetScope", c_void_p),
|
|
("ResetScope", c_void_p),
|
|
("GetScopeSymbolGroup", c_void_p),
|
|
("CreateSymbolGroup", c_void_p),
|
|
("StartSymbolMatch", c_void_p),
|
|
("GetNextSymbolMatch", c_void_p),
|
|
("EndSymbolMatch", c_void_p),
|
|
("Reload", c_void_p),
|
|
("GetSymbolPath", c_void_p),
|
|
("SetSymbolPath", c_void_p),
|
|
("AppendSymbolPath", c_void_p),
|
|
("GetImagePath", c_void_p),
|
|
("SetImagePath", c_void_p),
|
|
("AppendImagePath", c_void_p),
|
|
("GetSourcePath", c_void_p),
|
|
("GetSourcePathElement", c_void_p),
|
|
("SetSourcePath", c_void_p),
|
|
("AppendSourcePath", c_void_p),
|
|
("FindSourceFile", c_void_p),
|
|
("GetSourceFileLineOffsets", c_void_p),
|
|
("GetModuleVersionInformation", c_void_p),
|
|
("GetModuleNameString", ids_getmodulenamestring),
|
|
("GetConstantName", c_void_p),
|
|
("GetFieldName", c_void_p),
|
|
("GetTypeOptions", c_void_p),
|
|
("AddTypeOptions", c_void_p),
|
|
("RemoveTypeOptions", c_void_p),
|
|
("SetTypeOptions", c_void_p),
|
|
("GetNameByOffsetWide", c_void_p),
|
|
("GetOffsetByNameWide", c_void_p),
|
|
("GetNearNameByOffsetWide", c_void_p),
|
|
("GetLineByOffsetWide", c_void_p),
|
|
("GetOffsetByLineWide", c_void_p),
|
|
("GetModuleByModuleNameWide", c_void_p),
|
|
("GetSymbolModuleWide", c_void_p),
|
|
("GetTypeNameWide", c_void_p),
|
|
("GetTypeIdWide", c_void_p),
|
|
("GetFieldOffsetWide", c_void_p),
|
|
("GetSymbolTypeIdWide", c_void_p),
|
|
("GetScopeSymbolGroup2", ids_getscopesymbolgroup2),
|
|
("CreateSymbolGroup2", c_void_p),
|
|
("StartSymbolMatchWide", c_void_p),
|
|
("GetNextSymbolMatchWide", c_void_p),
|
|
("ReloadWide", c_void_p),
|
|
("GetSymbolPathWide", c_void_p),
|
|
("SetSymbolPathWide", c_void_p),
|
|
("AppendSymbolPathWide", c_void_p),
|
|
("GetImagePathWide", c_void_p),
|
|
("SetImagePathWide", c_void_p),
|
|
("AppendImagePathWide", c_void_p),
|
|
("GetSourcePathWide", c_void_p),
|
|
("GetSourcePathElementWide", c_void_p),
|
|
("SetSourcePathWide", c_void_p),
|
|
("AppendSourcePathWide", c_void_p),
|
|
("FindSourceFileWide", c_void_p),
|
|
("GetSourceFileLineOffsetsWide", c_void_p),
|
|
("GetModuleVersionInformationWide", c_void_p),
|
|
("GetModuleNameStringWide", c_void_p),
|
|
("GetConstantNameWide", c_void_p),
|
|
("GetFieldNameWide", c_void_p),
|
|
("IsManagedModule", c_void_p),
|
|
("GetModuleByModuleName2", c_void_p),
|
|
("GetModuleByModuleName2Wide", c_void_p),
|
|
("GetModuleByOffset2", c_void_p),
|
|
("AddSyntheticModule", c_void_p),
|
|
("AddSyntheticModuleWide", c_void_p),
|
|
("RemoveSyntheticModule", c_void_p),
|
|
("GetCurrentScopeFrameIndex", ids_getcurrentscopeframeindex),
|
|
("SetScopeFrameByIndex", ids_setscopeframebyindex),
|
|
("SetScopeFromJitDebugInfo", c_void_p),
|
|
("SetScopeFromStoredEvent", c_void_p),
|
|
("OutputSymbolByOffset", c_void_p),
|
|
("GetFunctionEntryByOffset", c_void_p),
|
|
("GetFieldTypeAndOffset", c_void_p),
|
|
("GetFieldTypeAndOffsetWide", c_void_p),
|
|
("AddSyntheticSymbol", c_void_p),
|
|
("AddSyntheticSymbolWide", c_void_p),
|
|
("RemoveSyntheticSymbol", c_void_p),
|
|
("GetSymbolEntriesByOffset", c_void_p),
|
|
("GetSymbolEntriesByName", ids_getsymbolentriesbyname),
|
|
("GetSymbolEntriesByNameWide", c_void_p),
|
|
("GetSymbolEntryByToken", c_void_p),
|
|
("GetSymbolEntryInformation", ids_getsymbolentryinformation),
|
|
("GetSymbolEntryString", ids_getsymbolentrystring),
|
|
("GetSymbolEntryStringWide", c_void_p),
|
|
("GetSymbolEntryOffsetRegions", c_void_p),
|
|
("GetSymbolEntryBySymbolEntry", c_void_p),
|
|
("GetSourceEntriesByOffset", c_void_p),
|
|
("GetSourceEntriesByLine", c_void_p),
|
|
("GetSourceEntriesByLineWide", c_void_p),
|
|
("GetSourceEntryString", c_void_p),
|
|
("GetSourceEntryStringWide", c_void_p),
|
|
("GetSourceEntryOffsetRegions", c_void_p),
|
|
("GetsourceEntryBySourceEntry", c_void_p),
|
|
("GetScopeEx", c_void_p),
|
|
("SetScopeEx", c_void_p),
|
|
("GetNameByInlineContext", ids_getnamebyinlinecontext),
|
|
("GetNameByInlineContextWide", c_void_p),
|
|
("GetLineByInlineContext", ids_getlinebyinlinecontext),
|
|
("GetLineByInlineContextWide", c_void_p),
|
|
("OutputSymbolByInlineContext", c_void_p),
|
|
("GetCurrentScopeFrameIndexEx", c_void_p),
|
|
("SetScopeFrameByIndexEx", c_void_p)
|
|
]
|
|
|
|
IDebugSymbols5._fields_ = [("lpVtbl", POINTER(IDebugSymbols5Vtbl))]
|
|
|
|
SymbolId = namedtuple("SymbolId", ["ModuleBase", "Id"])
|
|
SymbolEntry = namedtuple("SymbolEntry", ["ModuleBase", "Offset", "Id", "Arg64", "Size", "Flags", "TypeId", "NameSize", "Token", "Tag", "Arg32"])
|
|
DebugModuleParams = namedtuple("DebugModuleParams", ["Base", "Size", "TimeDateStamp", "Checksum", "Flags", "SymbolType", "ImageNameSize", "ModuleNameSize", "LoadedImageNameSize", "SymbolFileNameSize", "MappedImageNameSize"])
|
|
|
|
class SymTags(IntEnum):
|
|
Null = 0
|
|
Exe = 1
|
|
SymTagFunction = 5
|
|
|
|
def make_debug_module_params(cdata):
|
|
fieldvalues = map(lambda y: getattr(cdata, y), DebugModuleParams._fields)
|
|
return DebugModuleParams(*fieldvalues)
|
|
|
|
class Symbols(object):
|
|
def __init__(self, symbols):
|
|
self.ptr = symbols
|
|
self.symbols = symbols.contents
|
|
self.vt = self.symbols.lpVtbl.contents
|
|
# Keep some handy ulongs for passing into C methods.
|
|
self.ulong = c_ulong()
|
|
self.ulong64 = c_ulonglong()
|
|
|
|
def GetCurrentScopeFrameIndex(self):
|
|
res = self.vt.GetCurrentScopeFrameIndex(self.symbols, byref(self.ulong))
|
|
aborter(res, "GetCurrentScopeFrameIndex")
|
|
return self.ulong.value
|
|
|
|
def SetScopeFrameByIndex(self, idx):
|
|
res = self.vt.SetScopeFrameByIndex(self.symbols, idx)
|
|
aborter(res, "SetScopeFrameByIndex", ignore=[E_EINVAL])
|
|
return res != E_EINVAL
|
|
|
|
def GetOffsetByName(self, name):
|
|
res = self.vt.GetOffsetByName(self.symbols, name.encode("ascii"), byref(self.ulong64))
|
|
aborter(res, "GetOffsetByName {}".format(name))
|
|
return self.ulong64.value
|
|
|
|
def GetNearNameByOffset(self, addr):
|
|
ptr = create_string_buffer(256)
|
|
pulong = c_ulong()
|
|
disp = c_ulonglong()
|
|
# Zero arg -> "delta" indicating how many symbols to skip
|
|
res = self.vt.GetNearNameByOffset(self.symbols, addr, 0, ptr, 255, byref(pulong), byref(disp))
|
|
if res == E_NOINTERFACE:
|
|
return "{noname}"
|
|
aborter(res, "GetNearNameByOffset")
|
|
ptr[255] = '\0'.encode("ascii")
|
|
return '{}+{}'.format(string_at(ptr).decode("ascii"), disp.value)
|
|
|
|
def GetModuleByModuleName2(self, name):
|
|
# First zero arg -> module index to search from, second zero arg ->
|
|
# DEBUG_GETMOD_* flags, none of which we use.
|
|
res = self.vt.GetModuleByModuleName2(self.symbols, name, 0, 0, None, byref(self.ulong64))
|
|
aborter(res, "GetModuleByModuleName2")
|
|
return self.ulong64.value
|
|
|
|
def GetScopeSymbolGroup2(self):
|
|
retptr = POINTER(IDebugSymbolGroup2)()
|
|
res = self.vt.GetScopeSymbolGroup2(self.symbols, ScopeGroupFlags.DEBUG_SCOPE_GROUP_ALL, None, retptr)
|
|
aborter(res, "GetScopeSymbolGroup2")
|
|
return SymbolGroup(retptr)
|
|
|
|
def GetSymbolEntryString(self, idx, module):
|
|
symid = DEBUG_MODULE_AND_ID()
|
|
symid.ModuleBase = module
|
|
symid.Id = idx
|
|
ptr = create_string_buffer(1024)
|
|
# Zero arg is the string index -- symbols can have multiple names, for now
|
|
# only support the first one.
|
|
res = self.vt.GetSymbolEntryString(self.symbols, symid, 0, ptr, 1023, byref(self.ulong))
|
|
aborter(res, "GetSymbolEntryString")
|
|
return string_at(ptr).decode("ascii")
|
|
|
|
def GetSymbolEntryInformation(self, module, theid):
|
|
symid = DEBUG_MODULE_AND_ID()
|
|
symentry = DEBUG_SYMBOL_ENTRY()
|
|
symid.ModuleBase = module
|
|
symid.Id = theid
|
|
res = self.vt.GetSymbolEntryInformation(self.symbols, symid, symentry)
|
|
aborter(res, "GetSymbolEntryInformation")
|
|
# Fetch fields into SymbolEntry object
|
|
fields = map(lambda x: getattr(symentry, x), SymbolEntry._fields)
|
|
return SymbolEntry(*fields)
|
|
|
|
def GetSymbolEntriesByName(self, symstr):
|
|
# Initial query to find number of symbol entries
|
|
res = self.vt.GetSymbolEntriesByName(self.symbols, symstr.encode("ascii"), 0, None, 0, byref(self.ulong))
|
|
aborter(res, "GetSymbolEntriesByName")
|
|
|
|
# Build a buffer and query for 'length' entries
|
|
length = self.ulong.value
|
|
symrecs = (DEBUG_MODULE_AND_ID * length)()
|
|
# Zero arg -> flags, of which there are none defined.
|
|
res = self.vt.GetSymbolEntriesByName(self.symbols, symstr.encode("ascii"), 0, symrecs, length, byref(self.ulong))
|
|
aborter(res, "GetSymbolEntriesByName")
|
|
|
|
# Extract 'length' number of SymbolIds
|
|
length = self.ulong.value
|
|
def extract(x):
|
|
sym = symrecs[x]
|
|
return SymbolId(sym.ModuleBase, sym.Id)
|
|
return [extract(x) for x in range(length)]
|
|
|
|
def GetSymbolPath(self):
|
|
# Query for length of buffer to allocate
|
|
res = self.vt.GetSymbolPath(self.symbols, None, 0, byref(self.ulong))
|
|
aborter(res, "GetSymbolPath", ignore=[S_FALSE])
|
|
|
|
# Fetch 'length' length symbol path string
|
|
length = self.ulong.value
|
|
arr = create_string_buffer(length)
|
|
res = self.vt.GetSymbolPath(self.symbols, arr, length, byref(self.ulong))
|
|
aborter(res, "GetSymbolPath")
|
|
|
|
return string_at(arr).decode("ascii")
|
|
|
|
def GetSourcePath(self):
|
|
# Query for length of buffer to allocate
|
|
res = self.vt.GetSourcePath(self.symbols, None, 0, byref(self.ulong))
|
|
aborter(res, "GetSourcePath", ignore=[S_FALSE])
|
|
|
|
# Fetch a string of len 'length'
|
|
length = self.ulong.value
|
|
arr = create_string_buffer(length)
|
|
res = self.vt.GetSourcePath(self.symbols, arr, length, byref(self.ulong))
|
|
aborter(res, "GetSourcePath")
|
|
|
|
return string_at(arr).decode("ascii")
|
|
|
|
def SetSourcePath(self, string):
|
|
res = self.vt.SetSourcePath(self.symbols, string.encode("ascii"))
|
|
aborter(res, "SetSourcePath")
|
|
return
|
|
|
|
def GetModuleParameters(self, base):
|
|
self.ulong64.value = base
|
|
params = DEBUG_MODULE_PARAMETERS()
|
|
# Fetch one module params struct, starting at idx zero
|
|
res = self.vt.GetModuleParameters(self.symbols, 1, byref(self.ulong64), 0, byref(params))
|
|
aborter(res, "GetModuleParameters")
|
|
return make_debug_module_params(params)
|
|
|
|
def GetSymbolOptions(self):
|
|
res = self.vt.GetSymbolOptions(self.symbols, byref(self.ulong))
|
|
aborter(res, "GetSymbolOptions")
|
|
return SymbolOptionFlags(self.ulong.value)
|
|
|
|
def SetSymbolOptions(self, opts):
|
|
assert isinstance(opts, SymbolOptionFlags)
|
|
res = self.vt.SetSymbolOptions(self.symbols, opts.value)
|
|
aborter(res, "SetSymbolOptions")
|
|
return
|
|
|
|
def GetLineByOffset(self, offs):
|
|
# Initial query for filename buffer size
|
|
res = self.vt.GetLineByOffset(self.symbols, offs, None, None, 0, byref(self.ulong), None)
|
|
if res == E_FAIL:
|
|
return None # Sometimes we just can't get line numbers, of course
|
|
aborter(res, "GetLineByOffset", ignore=[S_FALSE])
|
|
|
|
# Allocate filename buffer and query for line number too
|
|
filenamelen = self.ulong.value
|
|
text = create_string_buffer(filenamelen)
|
|
line = c_ulong()
|
|
res = self.vt.GetLineByOffset(self.symbols, offs, byref(line), text, filenamelen, byref(self.ulong), None)
|
|
aborter(res, "GetLineByOffset")
|
|
|
|
return string_at(text).decode("ascii"), line.value
|
|
|
|
def GetModuleNameString(self, whichname, base):
|
|
# Initial query for name string length
|
|
res = self.vt.GetModuleNameString(self.symbols, whichname, DEBUG_ANY_ID, base, None, 0, byref(self.ulong))
|
|
aborter(res, "GetModuleNameString", ignore=[S_FALSE])
|
|
|
|
module_name_len = self.ulong.value
|
|
module_name = (c_char * module_name_len)()
|
|
res = self.vt.GetModuleNameString(self.symbols, whichname, DEBUG_ANY_ID, base, module_name, module_name_len, None)
|
|
aborter(res, "GetModuleNameString")
|
|
|
|
return string_at(module_name).decode("ascii")
|
|
|
|
def GetNameByInlineContext(self, pc, ctx):
|
|
# None args -> ignore output name size and displacement
|
|
buf = create_string_buffer(256)
|
|
res = self.vt.GetNameByInlineContext(self.symbols, pc, ctx, buf, 255, None, None)
|
|
aborter(res, "GetNameByInlineContext")
|
|
return string_at(buf).decode("ascii")
|
|
|
|
def GetLineByInlineContext(self, pc, ctx):
|
|
# None args -> ignore output filename size and displacement
|
|
buf = create_string_buffer(256)
|
|
res = self.vt.GetLineByInlineContext(self.symbols, pc, ctx, byref(self.ulong), buf, 255, None, None)
|
|
aborter(res, "GetLineByInlineContext")
|
|
return string_at(buf).decode("ascii"), self.ulong.value
|
|
|
|
def get_all_symbols(self):
|
|
main_module_name = self.get_exefile_module_name()
|
|
idnumbers = self.GetSymbolEntriesByName("{}!*".format(main_module_name))
|
|
lst = []
|
|
for symid in idnumbers:
|
|
s = self.GetSymbolEntryString(symid.Id, symid.ModuleBase)
|
|
symentry = self.GetSymbolEntryInformation(symid.ModuleBase, symid.Id)
|
|
lst.append((s, symentry))
|
|
return lst
|
|
|
|
def get_all_functions(self):
|
|
syms = self.get_all_symbols()
|
|
return [x for x in syms if x[1].Tag == SymTags.SymTagFunction]
|
|
|
|
def get_all_modules(self):
|
|
params = DEBUG_MODULE_PARAMETERS()
|
|
idx = 0
|
|
res = 0
|
|
all_modules = []
|
|
while res != E_EINVAL:
|
|
res = self.vt.GetModuleParameters(self.symbols, 1, None, idx, byref(params))
|
|
aborter(res, "GetModuleParameters", ignore=[E_EINVAL])
|
|
all_modules.append(make_debug_module_params(params))
|
|
idx += 1
|
|
return all_modules
|
|
|
|
def get_exefile_module(self):
|
|
all_modules = self.get_all_modules()
|
|
reduce_func = lambda x, y: y if y.Flags & DebugModuleFlags.DEBUG_MODULE_EXE_MODULE else x
|
|
main_module = reduce(reduce_func, all_modules, None)
|
|
if main_module is None:
|
|
raise Exception("Couldn't find the exefile module")
|
|
return main_module
|
|
|
|
def get_module_name(self, base):
|
|
return self.GetModuleNameString(DebugModuleNames.DEBUG_MODNAME_MODULE, base)
|
|
|
|
def get_exefile_module_name(self):
|
|
return self.get_module_name(self.get_exefile_module().Base)
|