如何寫個程序找出現有C++工程里的所有函數?

最近試過寫點簡單語法分析,發現還是底子不夠,好多分析錯誤的。

我在想VS編譯時肯定有函數信息,這個能不能拿出來?

或者說繼續鑽研語法分析,這裡有什麼技巧?


請用Clang:Introduction to the Clang AST

遍歷一下Clang所parse出來的AST里的所有FunctionDecl就好了。

後面有答案提到了正好做這件事的教程,把鏈接借用過來:結構化編譯器前端 Clang 介紹

至於Visual C++,它的前端(c1xx.dll)雖然會生成AST給後端(c2.dll),但它是通過5個臨時文件傳遞的,而這些文件的格式沒任何對外公開的文檔,想自己解析它多麻煩吶。還是乖乖用Clang好了。

=========================================================

如果還是對Visual C++念念不舍,請去找找Phoenix Compiler的下載。Phoenix SDK June 2008 CTP可以(只能)插在Visual Studio 2008上用。

安裝Phoenix SDK之後,它帶的c2.dll可以替代原本Visual C++的編譯器後端,而且裡面的大量功能都有API暴露出來,要想獲取所有C++函數聲明的話寫個簡單的plugin就好了。

在Phoenix SDK里,有個FuncNames sample plugin,可以把所有被編譯的C++函數的名字(mangled name)輸出出來;這些mangled name可以用Visual C++自帶的undname.exe(name undecorator)來轉換回到人可讀的形式。

這plugin可以用C#或C++來寫。C#版,最核心的部分其實就這樣:

public class FuncNamePhase: Phx.Phases.Phase
{
// ...

protected override void Execute(Phx.Unit unit)
{
if (!unit.IsFunctionUnit) return;

var function = unit.AsFunctionUnit;
Phx.Output.WriteLine("Function {0}", function.NameString);
}
}

很方便對不對? &>_&<

=========================================================

要自己讀Visual C++在debug編譯模式生成的PDB文件的話也行。請參考:

PDB Files: What Every Developer Must Know

How to Inspect the Content of a Program Database (PDB) File

可以藉助Debug Interface Access SDK來讀取PDB文件的內容。

為啥強調debug模式生成的PDB文件呢?因為release模式生成的PDB文件損失的信息比較多,如果目的是獲取項目里的函數的列表的話,用release模式得不償失。

CCI里也有一個PdbReader,不過我沒用它來讀過Visual C++生成的PDB文件,不知道能不能用。


我記得ibm有篇教學文檔就是講用clang獲得所有函數的

結構化編譯器前端 Clang 介紹

我記得沒錯


想要從VS編譯的結果拿出來的話,也可以通過 DIA來查詢項目生成的符號文件(PDB)裡面的所有的函數和聲明(主要查詢SymTagFunction就行了)。這裡就個一個例子,從符號文件裡面還原了項目裡面所有的 class 定義。


如果是debug版生成了帶調試信息的pdb文件,可以從pdb文件中讀取信息.

Is there a way to read a C/C++ PDB file contents?


Linux里有個工具叫nm。編譯出.o文件之後,可以用

nm --defined-only *.o | c++filt

查看每個文件里的函數名。可以看看是不是你想要的。

Windows里對應的工具是dumpbin.exe,或者用cygwin裡面的nm。

參考連接:

symbols - Microsoft equivalent of the nm command

Description of the DUMPBIN utility

DUMPBIN Reference


直接上代碼:

gcc中實現,在cfg圖構建好之後添加即可 ,以下使用gcc插件實現:

int plugin_init (struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)

{

int i;

int argc = plugin_info-&>argc;

struct plugin_argument *argv = plugin_info-&>argv;

if (!plugin_default_version_check (version, gcc_version))

return 1;

register_callback(plugin_info-&>base_name, PLUGIN_ALL_IPA_PASSES_END,

(plugin_callback_func)GetFunction_Main, NULL);

return 0;

}

void GetFunction_Main(){

printf(("
========Start analyzing file %s.========
", in_fnames[0]));

/*traverse the call graph*/

int count_sum= 0;

struct cgraph_node *node; //cgraph_node is a call graph node. It stans for a function.

for (node = cgraph_nodes; node; node=node-&>next) {

count_sum++;

printf("Current function name: %s.
", current_function_name());

/*set the current function to NULL.*/

}

}


找個開源的能顯示函數的IDE,或者代碼閱讀器,看看源碼。


推薦閱讀:

為什麼int型的負數會比字元串函數length()返回的值大?
C++ 用輸入的變數作為數組長度是壞習慣嗎?
在oi/acm中,有什麼冷門但好用的stl函數?
如何向完全不懂編程的小夥伴解釋「程序寫死」?
為什麼 C++ 只比 VBA 快 4倍?

TAG:編程 | 軟體測試 | C | 編譯器 |