简体   繁体   English

如何通过 dbghelp 获取我的项目的托管(dotnet)和本机(C++)调用堆栈?

[英]How to obtain both managed(dotnet) and native(C++) callstack of my project by dbghelp?

My project contains managed part( dotnet ) and native( C++ ) part.我的项目包含托管部分( dotnet )和本机( C++ )部分。 I want to hook Winapi CreateFiles in my project by detours and log callstack.我想通过绕道和记录调用堆栈在我的项目中挂钩 Winapi CreateFiles Now I have obtained a native callstack by invoking CaptureStackBackTrace and SymFromAddr api in dbghelp .现在我通过在dbghelp中调用CaptureStackBackTraceSymFromAddr api 获得了本机调用堆栈。 But I meet some troubles when those functions are used in dotnet .但是在dotnet中使用这些功能时会遇到一些麻烦。 as shown in the following picture, it can obtain correct callstack of native code(22, 21, 1, 0) but not work for managed code(20-2).如下图所示,它可以获得正确的本机代码调用堆栈(22、21、1、0),但不适用于托管代码(20-2)。 may I have some methods to obtain both managed(dotnet) and un-managed(C++) callstack correctly?我可以有一些方法来正确获取托管(dotnet)和非托管(C++)调用堆栈吗? or maybe you have the best method to get callstack, could you help me?或者也许你有最好的方法来获取调用堆栈,你能帮我吗?

dotnet produce: dotnet 产生:

public class CreateFileOrFolder
{
    public void writeToFile(string pathString) {
        System.IO.File.Create(pathString);
    }

    static void Main()
    {
        System.Console.WriteLine("Press any key to start.\n");
        System.Console.ReadKey();
    
        string fileName = "c.txt";
        string pathString = System.IO.Path.Combine(@"D:\JunFiles\testDotNetProceduce", fileName);

        // Verify the path that you have constructed.
        Console.WriteLine("Path to my file: {0}\n", pathString);
        CreateFileOrFolder creater = new CreateFileOrFolder();
        if (!System.IO.File.Exists(pathString)) {
            creater.writeToFile(pathString);
        }
        else
        {
            System.IO.File.Delete(pathString);
            Console.WriteLine("File \"{0}\" already exists. but now it is deleted\n", fileName);
            creater.writeToFile(pathString);
        }
    }

}

detours hook function: detours钩子函数:

HANDLE(*__stdcall oldCreateFile)(LPCWSTR,
    DWORD,
    DWORD,
    LPSECURITY_ATTRIBUTES,
    DWORD,
    DWORD,
    HANDLE) = CreateFileW;

HANDLE WINAPI newCreateFile(
    _In_ LPCWSTR lpFileName,
    _In_ DWORD dwDesiredAccess,
    _In_ DWORD dwShareMode,
    _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
    _In_ DWORD dwCreationDisposition,
    _In_ DWORD dwFlagsAndAttributes,
    _In_opt_ HANDLE hTemplateFile
) {

    static BOOL state = FALSE;
    printStack();
    symbolSolve(process);
    printf("HOOK sucess!\n");
    std::cout << current_working_directory() << endl;
    
    wchar_t newFileName[] = L".\\newFile.txt";
    return oldCreateFile(
        newFileName, // L".\\NewFile.txt",     // Filename
        //lpFileName,
        dwDesiredAccess,          // Desired access
        dwShareMode,        // Share mode
        lpSecurityAttributes,                   // Security attributes
        dwCreationDisposition,             // Creates a new file, only if it doesn't already exist
        dwFlagsAndAttributes,  // Flags and attributes
        NULL);
}

get callstack:获取调用栈:

#define STACK_INFO_LEN  200
static HANDLE process;
unsigned int   i;
void* stack[100];
unsigned short frames;
SYMBOL_INFO* symbol;
std::queue<std::pair<void*, unsigned short>> myQueue;

PDWORD hashValue = (PDWORD)malloc(sizeof(DWORD));

void printStack(void)
{
    frames = CaptureStackBackTrace(0, 100, stack, hashValue);
    void* stackTmp = stack;
}

DWORD WINAPI symbolSolve(LPVOID p) {
    int myqueue_size = myQueue.size();
    char* szBriefInfo = NULL;
    static const int MAX_STACK_FRAMES = 12;
    void* pStack[MAX_STACK_FRAMES];
    static char szStackInfo[STACK_INFO_LEN * MAX_STACK_FRAMES];
    static char szFrameInfo[STACK_INFO_LEN];
    if (szBriefInfo == NULL) {
        strcpy_s(szStackInfo, "stack traceback:\n");
    }
    else {
        strcpy_s(szStackInfo, szBriefInfo);
    }

    symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
    symbol->MaxNameLen = 255;
    symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
    IMAGEHLP_LINE line;
    line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
    DWORD displacementLine = 0;
    std::string strs = "";
    strs += std::to_string(*hashValue);
    for (i = 0; i < frames; i++) {
        SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
        BOOL ret = SymGetLineFromAddr64(process, (DWORD64)(stack[i]), &displacementLine, &line);
        _snprintf_s(szFrameInfo, sizeof(szFrameInfo), "%i: %s - 0x%0X ", frames - i - 1, symbol->Name, symbol->Address);
        strcat_s(szStackInfo, szFrameInfo);

        if (ret) {
            _snprintf_s(szFrameInfo, sizeof(szFrameInfo), " | %s at %o \n", line.FileName, line.LineNumber);
            strcat_s(szStackInfo, szFrameInfo);
        }
        else {
            _snprintf_s(szFrameInfo, sizeof(szFrameInfo), "|error %d \n", GetLastError());
            strcat_s(szStackInfo, szFrameInfo);
        }
    }
    printf("%s \n", szStackInfo);
    free(symbol);
    return 0;
}

result:结果:

在此处输入图像描述

The short answer is that dbhlp can't help with the managed parts of the stack walk.简短的回答是 dbhlp 无法帮助处理堆栈遍历的托管部分。

It can be done, as windbg can do mixed mode stacks but it's specific to the version of .net and it also requires access to the full process memory to do it.可以这样做,因为 windbg 可以进行混合模式堆栈,但它特定于 .net 的版本,并且还需要访问完整的进程内存才能做到这一点。 I don't think the results from CaptureStackBackTrace will be enough, although since you are doing this in-process you may get away with it.我认为 CaptureStackBackTrace 的结果还不够,尽管由于您是在进程中执行此操作,因此您可能会侥幸逃脱。

See the Mixed Mode Stackwalk article, which should give you pointers in the right direction.请参阅Mixed Mode Stackwalk文章,它应该为您提供正确方向的指示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM