Skip to content

Instantly share code, notes, and snippets.

@HoShiMin
Created September 24, 2018 21:03
Show Gist options
  • Select an option

  • Save HoShiMin/779d1c5e96e50a653ca43511b7bcb69a to your computer and use it in GitHub Desktop.

Select an option

Save HoShiMin/779d1c5e96e50a653ca43511b7bcb69a to your computer and use it in GitHub Desktop.

Revisions

  1. HoShiMin created this gist Sep 24, 2018.
    256 changes: 256 additions & 0 deletions SymParser.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,256 @@
    #include <windows.h>
    #include <vector>
    #include <string>
    #include "SymParser.h"

    // Using Wide-versions of DbgHelp functions:
    #define DBGHELP_TRANSLATE_TCHAR

    // Expose additional declarations from DbgHelp.h:
    #define _NO_CVCONST_H

    #include <dbghelp.h>
    #pragma comment(lib, "dbghelp.lib")

    SymParser::SymParser(OPTIONAL LPCWSTR SymbolsPath)
    : Initialized(FALSE), hProcess(GetCurrentProcess()), ModuleBase(NULL)
    {
    Initialized = SymInitialize(
    hProcess,
    SymbolsPath ? SymbolsPath : DefaultSymbolsPath,
    FALSE
    );
    }

    SymParser::~SymParser() {
    if (Initialized) SymCleanup(hProcess);
    }


    BOOL SymParser::LoadModule(LPCWSTR ModulePath, OPTIONAL DWORD64 ImageBase, OPTIONAL DWORD ImageSize) {
    ModuleBase = SymLoadModuleEx(hProcess, NULL, ModulePath, NULL, ImageBase, ImageSize, NULL, 0);
    return ModuleBase != NULL;
    }


    std::wstring SymParser::GetSymName(ULONG Index, OPTIONAL OUT PBOOL Status) {
    LPCWSTR Name = NULL;
    if (SymGetTypeInfo(hProcess, ModuleBase, Index, TI_GET_SYMNAME, &Name) && Name) {
    std::wstring SymName = Name;
    VirtualFree(const_cast<LPWSTR>(Name), 0, MEM_RELEASE);
    if (Status) *Status = TRUE;
    return SymName;
    }
    if (Status) *Status = FALSE;
    return L"";
    }

    std::wstring SymParser::GetSymTypeName(ULONG Index, OPTIONAL OUT PUINT64 BaseTypeSize, OPTIONAL OUT PBOOL Status) {
    if (!Index) return L"";

    UINT64 SymSize = GetSymSize(Index, Status);
    if (BaseTypeSize) *BaseTypeSize = SymSize;
    std::wstring TypeName = GetSymName(Index, Status);
    if (!TypeName.empty()) return TypeName;

    enum SymTagEnum Tag = GetSymTag(Index, Status);
    switch (Tag) {
    case SymTagBaseType: {
    enum SymParser::BasicType Type = GetSymBaseType(Index, Status);
    switch (Type) {
    case btNoType:
    TypeName = L"NO_TYPE";
    break;
    case btVoid:
    TypeName = L"VOID";
    break;
    case btChar:
    TypeName = L"CHAR";
    break;
    case btWChar:
    TypeName = L"WCHAR";
    break;
    case btInt:
    TypeName = SymSize == sizeof(INT64) ? L"INT64" : L"INT";
    break;
    case btUInt:
    TypeName = SymSize == sizeof(UINT64) ? L"UINT64" : L"UINT";
    break;
    case btFloat:
    TypeName = L"float";
    break;
    case btBCD:
    TypeName = L"BCD"; // Binary-coded decimal
    break;
    case btBool:
    TypeName = L"BOOL";
    break;
    case btLong:
    TypeName = SymSize == sizeof(LONGLONG) ? L"LONGLONG" : L"LONG";
    break;
    case btULong:
    TypeName = SymSize == sizeof(ULONGLONG) ? L"ULONGLONG" : L"ULONG";
    break;
    case btCurrency:
    TypeName = L"CurrencyType"; // ???
    break;
    case btDate:
    TypeName = L"DateType"; // ???
    break;
    case btVariant:
    TypeName = L"VariantType"; // ???
    break;
    case btComplex:
    TypeName = L"ComplexType"; // ???
    break;
    case btBit:
    TypeName = L"Bit";
    break;
    case btBSTR:
    TypeName = L"BSTR"; // Binary string
    break;
    case btHresult:
    TypeName = L"HRESULT";
    break;
    }
    break;
    }
    case SymTagPointerType: {
    ULONG Type = GetSymType(Index, Status);
    TypeName = GetSymTypeName(Type, BaseTypeSize, Status) + L"*";
    break;
    }
    case SymTagArrayType: {
    ULONG Type = GetSymArrayTypeId(Index, Status);
    TypeName = GetSymTypeName(Type, BaseTypeSize, Status);
    break;
    }
    default: {
    ULONG Type = GetSymType(Index, Status);
    TypeName = GetSymTypeName(Type, BaseTypeSize, Status);
    }
    }

    return TypeName;
    }

    UINT64 SymParser::GetSymSize(ULONG Index, OPTIONAL OUT PBOOL Status) {
    UINT64 Size = 0;
    BOOL SymStatus = SymGetTypeInfo(hProcess, ModuleBase, Index, TI_GET_LENGTH, &Size);
    if (Status) *Status = SymStatus;
    return Size;
    }

    ULONG SymParser::GetSymOffset(ULONG Index, OPTIONAL OUT PBOOL Status) {
    ULONG Offset = 0;
    BOOL SymStatus = SymGetTypeInfo(hProcess, ModuleBase, Index, TI_GET_OFFSET, &Offset);
    if (Status) *Status = SymStatus;
    return Offset;
    }

    ULONG SymParser::GetSymAddressOffset(ULONG Index, OPTIONAL OUT PBOOL Status) {
    ULONG Offset = 0;
    BOOL SymStatus = SymGetTypeInfo(hProcess, ModuleBase, Index, TI_GET_ADDRESSOFFSET, &Offset);
    if (Status) *Status = SymStatus;
    return Offset;
    }

    ULONG SymParser::GetSymBitPosition(ULONG Index, OPTIONAL OUT PBOOL Status) {
    ULONG BitPosition = 0;
    BOOL SymStatus = SymGetTypeInfo(hProcess, ModuleBase, Index, TI_GET_BITPOSITION, &BitPosition);
    if (Status) *Status = SymStatus;
    return BitPosition;
    }

    ULONG SymParser::GetSymTypeId(ULONG Index, OPTIONAL OUT PBOOL Status) {
    ULONG TypeId = 0;
    BOOL SymStatus = SymGetTypeInfo(hProcess, ModuleBase, Index, TI_GET_TYPEID, &TypeId);
    if (Status) *Status = SymStatus;
    return TypeId;
    }

    ULONG SymParser::GetSymArrayTypeId(ULONG Index, OPTIONAL OUT PBOOL Status) {
    ULONG TypeId = 0;
    BOOL SymStatus = SymGetTypeInfo(hProcess, ModuleBase, Index, TI_GET_ARRAYINDEXTYPEID, &TypeId);
    if (Status) *Status = SymStatus;
    return TypeId;
    }

    enum SymTagEnum SymParser::GetSymTag(ULONG Index, OPTIONAL OUT PBOOL Status) {
    ULONG Tag = 0;
    BOOL SymStatus = SymGetTypeInfo(hProcess, ModuleBase, Index, TI_GET_SYMTAG, &Tag);
    if (Status) *Status = SymStatus;
    return static_cast<enum SymTagEnum>(Tag);
    }

    enum SymParser::BasicType SymParser::GetSymType(ULONG Index, OPTIONAL OUT PBOOL Status) {
    ULONG Type = 0;
    BOOL SymStatus = SymGetTypeInfo(hProcess, ModuleBase, Index, TI_GET_TYPE, &Type);
    if (Status) *Status = SymStatus;
    return static_cast<enum BasicType>(Type);
    }

    enum SymParser::BasicType SymParser::GetSymBaseType(ULONG Index, OPTIONAL OUT PBOOL Status) {
    ULONG BasicType = 0;
    BOOL SymStatus = SymGetTypeInfo(hProcess, ModuleBase, Index, TI_GET_BASETYPE, &BasicType);
    if (Status) *Status = SymStatus;
    return static_cast<enum BasicType>(BasicType);
    }


    BOOL SymParser::DumpSymbol(LPCWSTR SymbolName, OUT SYM_INFO& SymInfo) {
    SymInfo = {};

    // Obtaining root symbol:
    const ULONG SymNameLength = 128;
    const ULONG SymInfoSize = sizeof(SYMBOL_INFO) + SymNameLength * sizeof(WCHAR);
    std::vector<BYTE> RootSymbolInfoBuffer(SymInfoSize);
    auto RootSymbolInfo = reinterpret_cast<PSYMBOL_INFO>(&RootSymbolInfoBuffer[0]);
    RootSymbolInfo->SizeOfStruct = SymInfoSize;
    BOOL Status = SymGetTypeFromName(hProcess, ModuleBase, SymbolName, RootSymbolInfo);
    if (!Status) return FALSE;

    ULONG RootIndex = RootSymbolInfo->Index;

    SymInfo.Name = GetSymName(RootIndex);
    SymInfo.Size = GetSymSize(RootIndex);
    SymInfo.Offset = GetSymOffset(RootIndex, &Status);
    if (!Status) SymInfo.Offset = GetSymAddressOffset(RootIndex);

    // Obtaining root symbol children count:
    ULONG ChildrenCount = 0;
    Status = SymGetTypeInfo(hProcess, ModuleBase, RootIndex, TI_GET_CHILDRENCOUNT, &ChildrenCount);
    if (!Status) return FALSE;

    SymInfo.Name = SymbolName;
    SymGetTypeInfo(hProcess, ModuleBase, RootIndex, TI_GET_LENGTH, &SymInfo.Size);

    if (ChildrenCount) {
    // Obtaining children indices:
    std::vector<BYTE> FindChildrenParamsBuffer(sizeof(TI_FINDCHILDREN_PARAMS) + ChildrenCount * sizeof(ULONG));
    auto Children = reinterpret_cast<TI_FINDCHILDREN_PARAMS*>(&FindChildrenParamsBuffer[0]);
    Children->Count = ChildrenCount;
    Status = SymGetTypeInfo(hProcess, ModuleBase, RootIndex, TI_FINDCHILDREN, Children);
    if (!Status) return FALSE;

    for (unsigned int i = 0; i < ChildrenCount; i++) {
    SYM_CHILD_ENTRY Entry = {};
    ULONG ChildIndex = Children->ChildId[i];
    ULONG TypeId = GetSymTypeId(ChildIndex);
    Entry.Name = GetSymName(ChildIndex);
    Entry.Size = GetSymSize(TypeId);
    Entry.Offset = GetSymOffset(ChildIndex);
    Entry.BitPosition = GetSymBitPosition(ChildIndex, &Entry.IsBitField);
    UINT64 BaseTypeSize = 0;
    Entry.TypeName = GetSymTypeName(TypeId, &BaseTypeSize);
    Entry.ElementsCount = BaseTypeSize != 0 ? Entry.Size / BaseTypeSize : 1;

    if (Entry.Name.empty()) Entry.Name = L"UNKNOWN_NAME";
    if (Entry.TypeName.empty()) Entry.TypeName = L"UNKNOWN_TYPE";

    SymInfo.Entries.emplace_back(Entry);
    }
    }

    return TRUE;
    }
    69 changes: 69 additions & 0 deletions SymParser.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,69 @@
    #pragma once

    class SymParser {
    private:
    // From cvconst.h:
    enum BasicType {
    btNoType = 0,
    btVoid = 1,
    btChar = 2,
    btWChar = 3,
    btInt = 6,
    btUInt = 7,
    btFloat = 8,
    btBCD = 9,
    btBool = 10,
    btLong = 13,
    btULong = 14,
    btCurrency = 25,
    btDate = 26,
    btVariant = 27,
    btComplex = 28,
    btBit = 29,
    btBSTR = 30,
    btHresult = 31
    };

    BOOL Initialized;
    HANDLE hProcess;
    DWORD64 ModuleBase;
    LPCWSTR DefaultSymbolsPath = L"srv*C:\\Symbols*https://msdl.microsoft.com/download/symbols";

    std::wstring GetSymName(ULONG Index, OPTIONAL OUT PBOOL Status = NULL);
    std::wstring GetSymTypeName(ULONG Index, OPTIONAL OUT PUINT64 BaseTypeSize = NULL, OPTIONAL OUT PBOOL Status = NULL);
    UINT64 GetSymSize(ULONG Index, OPTIONAL OUT PBOOL Status = NULL);
    ULONG GetSymOffset(ULONG Index, OPTIONAL OUT PBOOL Status = NULL);
    ULONG GetSymAddressOffset(ULONG Index, OPTIONAL OUT PBOOL Status = NULL);
    ULONG GetSymBitPosition(ULONG Index, OPTIONAL OUT PBOOL Status = NULL);
    ULONG GetSymTypeId(ULONG Index, OPTIONAL OUT PBOOL Status = NULL);
    ULONG GetSymArrayTypeId(ULONG Index, OPTIONAL OUT PBOOL Status = NULL);
    enum SymTagEnum GetSymTag(ULONG Index, OPTIONAL OUT PBOOL Status = NULL);
    enum BasicType GetSymType(ULONG Index, OPTIONAL OUT PBOOL Status = NULL);
    enum BasicType GetSymBaseType(ULONG Index, OPTIONAL OUT PBOOL Status = NULL);
    public:
    using SYM_CHILD_ENTRY = struct {
    std::wstring Name;
    std::wstring TypeName;
    UINT64 ElementsCount;
    UINT64 Size;
    ULONG Offset;
    BOOL IsBitField;
    ULONG BitPosition;
    };
    using SYM_INFO = struct {
    std::wstring Name;
    UINT64 Size;
    ULONG Offset;
    std::vector<SYM_CHILD_ENTRY> Entries;
    };

    SymParser(OPTIONAL LPCWSTR SymbolsPath = NULL);
    ~SymParser();

    BOOL IsInitialized() const { return Initialized; }

    // Load symbols for specified module (*.exe/*.dll/*.sys etc.):
    BOOL LoadModule(LPCWSTR ModulePath, OPTIONAL DWORD64 ImageBase = NULL, OPTIONAL DWORD ImageSize = 0);

    BOOL DumpSymbol(LPCWSTR SymbolName, OUT SYM_INFO& SymInfo);
    };