This reverts commit cb935f3456.
Discussion in D68708 advises that green dragon is being briskly
refurbished, and it's good to have this patch up testing it.
500 lines
20 KiB
Python
500 lines
20 KiB
Python
# 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)
|