青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

focus on linux, c/c++, lua

Walking the callstack [譯文 part1]

Walking the callstack

作者:Jochen Kalmbach

翻譯:Hefe

原文出處:www.codeproject.com

關鍵字:callstack, StackWalker

簡介

有些情況下,我們需要顯示當前線程的callstack,或是顯示其他我們感興趣的進程或線程的callstack,為此,我專門寫了這篇文章闡述如何獲得callstack

我寫這篇文章的主要目的如下:

1, 提供一些簡單的接口來生成callstack

2, 基于CPP的特性提供一些方法來用于重載

3, 隱藏具體API的實現

4, Callstack信息默認輸出在debug模式窗口(可以自己定制輸出方式)

5, 支持用戶提供的內存只讀函數

6, 編譯器支持VC5-VC8

7, 提供最便利的callstack生成方案

背景

目前MS已經提供API(StackWalker64)用來遍歷callstack。從win9x/w2k開始,這個接口就被包含在dbghelp.dll的庫中(NT上,取而代之的是imagehelp.dll),只是這個接口(StackWalk64)w2k之后被改名字了,在w2k之前叫StackWalk,沒有尾巴的64。這個工程只支持最新的Xxx64接口,如果你想在比較舊的平臺上運行,你可以去下載支持相關的平臺dll

最新版本的dbghelp.dll可以和windbg一起下載(譯者注:windbgMS發布的一款調試工具,當你下載并安裝的時候,相應的安裝目錄下會有dbghelp.dll文件)。同時也包含了symsrv.dll文件,這個文件主要用來激活MS的公共符號服務(這個服務主要用來獲取系統文件的調試信息)

如何使用代碼

StackWalker這個類的使用非常簡單。比如:如果你想獲得當前線程的callstack,你只需要初始化一個StackWalk的實例,然后調用ShowCallStack即可。(譯者注:一般我們需要繼承StackWalker這個類,然后聲明并初始化這個子類的實例)。

代碼演示1

#include <windows.h>
#include "StackWalker.h"
 
void Func5() { StackWalker sw; sw.ShowCallstack(); }
void Func4() { Func5(); }
void Func3() { Func4(); }
void Func2() { Func3(); }
void Func1() { Func2(); }
 
int main()
{
  Func1();
  return 0;
}

debug-output窗口生成相應的輸出如下:

[...] (output stripped)
d:\privat\Articles\stackwalker\stackwalker.cpp (736): StackWalker::ShowCallstack
d:\privat\Articles\stackwalker\main.cpp (4): Func5
d:\privat\Articles\stackwalker\main.cpp (5): Func4
d:\privat\Articles\stackwalker\main.cpp (6): Func3
d:\privat\Articles\stackwalker\main.cpp (7): Func2
d:\privat\Articles\stackwalker\main.cpp (8): Func1
d:\privat\Articles\stackwalker\main.cpp (13): main
f:\vs70builds\3077\vc\crtbld\crt\src\crt0.c (259): mainCRTStartup
77E614C7 (kernel32): (filename not available): _BaseProcessStart@4

你現在可以雙擊任意一行,VS會自動的跳轉到你想到的文件并定位到具體行。

定制你自己的輸出結構

如果你想直接把callstack輸出到文件或是使用其他的輸出結構(譯者注:比如英雄島項目中就是ITrace*),你只需要繼承StackWalker類即可。你有兩種選擇來實現自己的輸出結構:1,重寫OnOutput方法。2,重寫所有的OnXXX函數。當然從OO的思想來說,第一種方法是推薦的,符合KISS的原則。

演示代碼2
class MyStackWalker : public StackWalker
{
public:
  MyStackWalker() : StackWalker() {}
protected:
  virtual void OnOutput(LPCSTR szText)
     { printf(szText); StackWalker::OnOutput(szText); }
};

獲得callstack的具體信息

如果你想獲得關于callstack的具體信息(比如已加載的模塊,地址信息,以及錯誤信息),你可以重載下面提供的相應的方法。
演示代碼3
class StackWalker
{
protected:
  virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
  virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size,
     DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);
  virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);
  virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
};
上述的方法會在callstack的生成過程中被調用。

callstack的各種類別

StackWalker的構造函數中,如果你想針對具體的進程生成callstack,那你需要傳入具體的進程信息作為參數,比如進程ID和進程句柄,請看下面的兩個構造函數。

演示代碼4

class StackWalker
{
public:
  StackWalker(
     int options = OptionsAll,
     LPCSTR szSymPath = NULL,
     DWORD dwProcessId = GetCurrentProcessId(),
     HANDLE hProcess = GetCurrentProcess()
     );
  // Just for other processes with
  // default-values for options and symPath
  StackWalker(
     DWORD dwProcessId,
     HANDLE hProcess
     );
};

真正遍歷callstack的方法也就是下面的ShowCallstack()

演示代碼5

class StackWalker
{
public:
  BOOL ShowCallstack(
     HANDLE hThread = GetCurrentThread(),
     CONTEXT *context = NULL,
     PReadProcessMemoryRoutine readMemoryFunction = NULL,
     LPVOID pUserData = NULL
     );
};

顯示一個異常的callstack

利用這個StackWalker你同樣可以獲得一個異常句柄的callstack。你只需要寫一個異常過濾器即可。

演示代碼6

// The exception filter function:
LONG WINAPI ExpFilter(EXCEPTION_POINTERS* pExp, DWORD dwExpCode)
{
  StackWalker sw;
  sw.ShowCallstack(GetCurrentThread(), pExp->ContextRecord);
  return EXCEPTION_EXECUTE_HANDLER;
}
 
// This is how to catch an exception:
__try
{
  // do some ugly stuff...
}
__except (ExpFilter(GetExceptionInformation(), GetExceptionCode()))
{
}

本文要點

上下文與callstack

遍歷一個線程的callstack,你至少要知道以下兩點:

1, 當前線程的上下文context

線程的上下文主要是用來獲取當前IP指針(Instruction Pointer指令指針)SP(Stack Pointer)指針的值,有時候也用來獲取FP(Frame Pointer)指針的值。簡而言之,SPFP指針的區別在于:SP指針指向最近一次的堆棧地址,FP主要用來指向當前函數的地址,你可以參考以下的文檔來了解更多(Difference Between Stack Pointer and Frame Pointer.)。但是對于CPU來說,只有SP是必不可少的,FP是提供給編譯器用的,你可以取消FP的使用開關。

2, Callstack

Callstack其實就是一塊內存區域,它包含了調用者的所有的數據內容和地址信息。這些數據內容必須用來獲取callstack(譯者注:感覺這句話有點多余了,為了尊重作者,我還是保留了)。最重要的是:在完成stack-walking之前,這些數據內容必須保持不變。這也就是為什么在獲取有效callstack的時候,當前線程必須要被掛起的原因。如果你想遍歷當前線程的stack,那么你也就不能改變callstack的指針內容,也就是在上下文中聲明的寄存器指針內容。

初始化STACKFRAME64結構

為了能利用StackWalk64來成功的遍歷callstack,我們必須用有意義的值來初始化STACKFRAME64。在STACKFRAME64的文檔中,有一小段要點描述如下:

如果STACKFRAME64的兩個成員AddrPCAddrFrame沒有被初始化就作為參數傳給StackWalk64的話,那么這個函數在第一次被調用的時候就會失敗。

根據這篇文檔所述,大多數的程序只需要初始化AddrPCAddrFrame這兩個參數,而且這種方式在dbghelp.dll最新版本v5.6.3.7發布之前一直都是正確的。但是,現在你除了要初始化這兩個參數之外,還要初始化AddrStack這個參數。在發現一些麻煩和問題后,我和dbghelp開發小組討論了一下,并得到了如下的答案(2005-08-02,我的觀點是斜體文字)

1, 在所有的平臺下,AddrStack都要被設置成指向stack pointer(也就是ESP)。你當然可以公布AddsStack應該被設置,甚至你可以說最新版本的dbghelp必須要求這么做。

2, 現在的dbghelp版本,你應該遵循下面的做法:

a). 請使用StackWalk64

b). 請把參數AddrPC設置成指向當前指令指針,分別是EIP(x86)Rip(x64),stIIP(IA64)

c). 請把AddrStack設置成指向當前的SP指針,分別是ESP(x86)RSP(x64),IntSP(IA64)

d). 如果當前的Frame Pointer是有意義的,請把AddrFrame設置成指向當前的Frame Pointer,分別是EBP(x86)RBP(x64)[作者的斜體字部分:當時在VC2005B2的環境下,該寄存器無法使用,取而代之的是Rdi]RsBSP(IA64)StackWalk64會在沒有必要的情況忽略這個參數的值。

e). IA64的平臺下請把AddrStore設置成指向RsBSP


posted on 2010-10-20 10:24 zuhd 閱讀(828) 評論(1)  編輯 收藏 引用 所屬分類: c/c++

評論

# re: Walking the callstack [譯文 part1] 2010-10-28 16:57 ugg boots buy

但是對于CPU來說,只有SP是必不可少的,FP是提供給編譯器用的,你可以取消FP的使用開關。<strong><a href="http://www.uggbootskaufende.com/">ugg boots tall</a></strong>  回復  更多評論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产亚洲电影| 亚洲免费高清| 狼狼综合久久久久综合网| 国产日韩欧美一区二区| 欧美诱惑福利视频| 狠狠入ady亚洲精品经典电影| 一区二区视频免费在线观看| 亚洲在线一区二区| 欧美激情一区二区三区在线视频| 久久久人成影片一区二区三区观看 | 亚洲福利久久| 欧美黄色小视频| 国产精品一区二区三区免费观看| 香蕉av777xxx色综合一区| 久久只精品国产| 亚洲一二三区精品| 久久9热精品视频| 一区二区三区欧美在线| 久久久久久亚洲精品杨幂换脸| 日韩视频永久免费观看| 久久aⅴ国产紧身牛仔裤| 亚洲影院色在线观看免费| 毛片一区二区| 欧美3dxxxxhd| 在线成人av| 久久综合伊人77777蜜臀| 性久久久久久久久| 亚洲最新视频在线播放| 亚洲精品小视频在线观看| 久久精品一区二区三区中文字幕| 午夜精品视频| 蜜臀av一级做a爰片久久| 国产精品一区毛片| 欧美亚洲一区| 亚洲精品一区二区三区av| 免费成人毛片| 亚洲国产精品专区久久| 国产精品免费在线| 亚洲一区二区精品在线| 久久久99爱| 这里只有精品视频在线| 久久精品视频亚洲| 免费视频一区二区三区在线观看| 激情综合色综合久久| 久久福利精品| 久久综合狠狠综合久久综合88 | 欧美亚州在线观看| 亚洲一区二区在线| 久久精品亚洲精品国产欧美kt∨| 国产欧美精品日韩精品| 久久久久久久久久久久久女国产乱 | 99re6热在线精品视频播放速度| 免费久久99精品国产自在现线| 欧美激情国产精品| 亚洲男人的天堂在线aⅴ视频| 国产精品欧美久久久久无广告| 亚久久调教视频| 亚洲电影在线播放| 亚洲尤物视频网| 亚洲电影免费| 国产美女精品一区二区三区| 久久综合影音| 亚洲一区二区三区四区视频| 欧美高清视频一区二区三区在线观看 | 性做久久久久久久久| 激情成人综合网| 国产精品久久久久久久久久久久| 久久久久国产精品www| 亚洲图片你懂的| 亚洲精品免费一二三区| 欧美成年人视频网站| 亚洲高清三级视频| 亚洲精品乱码视频| 亚洲天天影视| 欧美一区二区视频在线观看| 香蕉久久夜色精品国产使用方法| 香蕉成人啪国产精品视频综合网| 免费在线成人| 欧美成人69av| 欧美三级午夜理伦三级中文幕| 国产精品视频yy9299一区| 一区在线免费| 亚洲欧美清纯在线制服| 欧美韩国日本一区| 亚洲一区二区三区影院| 午夜精品福利一区二区三区av| 欧美国产一区在线| 亚洲精品日本| 亚洲欧美激情视频在线观看一区二区三区 | 欧美一区成人| 欧美a级大片| 国产精品福利片| 国产日韩在线亚洲字幕中文| 亚洲国产精品成人一区二区| av72成人在线| 久久综合网络一区二区| 亚洲激情国产精品| 亚洲欧美成人一区二区在线电影| 久久高清福利视频| 欧美日韩1234| 激情综合网址| 欧美成人日韩| 国产日韩亚洲欧美| 亚洲尤物影院| 最新日韩欧美| 久久综合亚州| 国产伊人精品| 欧美在线黄色| 99精品99久久久久久宅男| 久久久青草青青国产亚洲免观| 国产精品极品美女粉嫩高清在线| 韩国三级在线一区| 久久er精品视频| 在线综合亚洲| 国产精品综合视频| 宅男噜噜噜66一区二区66| 亚洲国产高清视频| 久久久久99| 99riav国产精品| 国产精品午夜国产小视频| 亚洲欧美国产一区二区三区| 亚洲综合国产精品| 国产日韩亚洲欧美| 欧美成人免费观看| 欧美日韩精品福利| 久久九九久精品国产免费直播| 久久激情综合| 日韩一级成人av| 先锋a资源在线看亚洲| 一区二区三区无毛| 亚洲国产欧美日韩| 国产精品视频观看| 欧美成年人视频网站| 欧美日韩成人综合天天影院| 久久成人18免费网站| 久久中文在线| 欧美一区二区视频观看视频| 久久在线免费视频| 欧美一二三区在线观看| 欧美激情小视频| 欧美在线观看网站| 欧美揉bbbbb揉bbbbb| 美女露胸一区二区三区| 国产精品久久久久三级| 欧美成年视频| 亚洲电影在线免费观看| 亚洲综合999| 欧美激情国产日韩| 欧美成人综合网站| 国产日韩精品在线播放| 在线视频欧美精品| 亚洲一区二区久久| 欧美精品导航| 亚洲精品一区二区在线观看| 影音先锋在线一区| 久久精品一区蜜桃臀影院| 午夜精品福利视频| 国产欧美精品日韩| 亚洲欧美日韩人成在线播放| 亚洲午夜性刺激影院| 欧美人成在线| 午夜视频在线观看一区| 欧美在线日韩| 亚洲二区在线| 99re6热在线精品视频播放速度| 欧美成人精品在线| 亚洲精品日韩在线观看| 一区二区日韩欧美| 国产精品美女在线| 久久这里有精品15一区二区三区| 亚洲高清不卡av| 先锋影音一区二区三区| 狠狠色综合日日| 欧美激情导航| 一区二区不卡在线视频 午夜欧美不卡在 | 欧美一区2区视频在线观看| 男女激情久久| 亚洲欧美另类综合偷拍| 国产一区二区三区无遮挡| 麻豆成人在线播放| 亚洲一区二区三区免费观看| 欧美1区2区视频| 欧美在线国产| 亚洲永久免费视频| 亚洲人成77777在线观看网| 国产精品视频网| 欧美另类女人| 蜜臀99久久精品久久久久久软件| 一区二区三区视频在线| 欧美激情国产高清| 久久人人精品| 久久精品国产第一区二区三区最新章节 | 艳妇臀荡乳欲伦亚洲一区| 国产一区二区三区高清| 国产午夜精品理论片a级大结局 | 欧美va天堂| 看片网站欧美日韩| 久久亚洲免费| 欧美在线日韩精品| 欧美一级久久久久久久大片|