本發(fā)明涉及程序分析領(lǐng)域,尤其涉及一種程序分析過(guò)程可視化方法及系統(tǒng)。
背景技術(shù):
目前程序分析工具或軟件都著重于程序分析的方法,具體的分析過(guò)程較抽象不直觀,不適合教學(xué)。在教學(xué)過(guò)程中,我們發(fā)現(xiàn)常規(guī)的程序分析軟件無(wú)法將程序分析的過(guò)程及結(jié)果直觀形象地展現(xiàn)給學(xué)生,分析過(guò)程也不可控。
例如代碼缺陷靜態(tài)檢查工具cppcheck,能對(duì)c程序進(jìn)行嚴(yán)格的邏輯缺陷檢測(cè),但該軟件只能給出檢測(cè)結(jié)果,中間的分析結(jié)果不可見(jiàn),分析過(guò)程不可控。
技術(shù)實(shí)現(xiàn)要素:
本發(fā)明要解決的問(wèn)題是提供一種程序分析過(guò)程可視化方法及系統(tǒng)。
為了解決上述技術(shù)問(wèn)題,本發(fā)明提供了程序分析過(guò)程可視化方法,包括:
步驟一、程序轉(zhuǎn)換為中間表示。其特征在于:使用開(kāi)源編譯器gcc攜帶參數(shù)-fdump-translation-unit,對(duì)源程序進(jìn)行詞法分析、語(yǔ)法分析,并生成程序的以節(jié)點(diǎn)為單位的中間表示;
步驟二、中間表示標(biāo)準(zhǔn)化處理。其特征在于中間表示的標(biāo)準(zhǔn)化處理方法:
將程序的中間表示規(guī)范化,包括規(guī)范每個(gè)節(jié)點(diǎn)成一行、刪除節(jié)點(diǎn)各個(gè)字段內(nèi)部多余的空格;
消除中間表示里與數(shù)據(jù)流、控制流無(wú)關(guān)的信息。首先將srcp字段值為源程序文件名的節(jié)點(diǎn)標(biāo)注為有用節(jié)點(diǎn),將srcp字段為其它值的節(jié)點(diǎn)標(biāo)注為無(wú)用節(jié)點(diǎn),其它節(jié)點(diǎn)為待定節(jié)點(diǎn);其次將有用節(jié)點(diǎn)的標(biāo)為待定的節(jié)點(diǎn)標(biāo)記為有用節(jié)點(diǎn),將無(wú)用節(jié)點(diǎn)的標(biāo)為待定的節(jié)點(diǎn)標(biāo)記為無(wú)用節(jié)點(diǎn),將沖突節(jié)點(diǎn)(父節(jié)點(diǎn)既有有用節(jié)點(diǎn)又有無(wú)用節(jié)點(diǎn))標(biāo)記為有用節(jié)點(diǎn);最后刪除無(wú)用節(jié)點(diǎn),并刪除每個(gè)節(jié)點(diǎn)中的srcp、algn、type字段及指向節(jié)點(diǎn)已被刪除的字段;
步驟三、中間表示的元級(jí)操作。其特征在于元級(jí)操作方法:在中間表示一級(jí)上對(duì)程序中的各種語(yǔ)法成分進(jìn)行增刪改查操作;
首先,將程序的中間表示轉(zhuǎn)換為鄰接表形式的抽象語(yǔ)法樹(shù)ast,其方法如下:
設(shè)程序的原始中間表示有n個(gè)節(jié)點(diǎn)信息,經(jīng)過(guò)標(biāo)準(zhǔn)化處理后剩余m個(gè)節(jié)點(diǎn),則將m個(gè)中間表示節(jié)點(diǎn)分別轉(zhuǎn)換為鄰接表的m個(gè)元素:
1)將字符串形式的中間表示節(jié)點(diǎn)拆分成“@kiname_type{attr:value}+”格式的子串,其中1<=ki<=n,1<=i<=m;
2)將非連續(xù)編號(hào)的m個(gè)ki映射為鄰接表的m個(gè)連續(xù)編號(hào),即建立編號(hào)映射表map={k1->1,k2->2,......km->m};
3)取map(ki)作為鄰接表元素的編號(hào);name_type作為鄰接表元素的類型;若value是“@kj”形式的子串,其中1<=kj<=n,1<=j<=m,則將編號(hào)為map(kj)的鄰接表元素作為當(dāng)前元素的孩子節(jié)點(diǎn),否則value直接作為當(dāng)前鄰接表元素的一個(gè)屬性值;
其次,在鄰接表上對(duì)程序進(jìn)行元級(jí)操作,其方法如下:
1)建立鄰接表形式的抽象語(yǔ)法樹(shù)與.net中的樹(shù)控件treenode之間的映射關(guān)系,將抽象語(yǔ)法樹(shù)以便于操作的控件的形式呈現(xiàn)給用戶。映射關(guān)系建立規(guī)則為:鄰接表的一個(gè)元素建立treenode中的一個(gè)node節(jié)點(diǎn),鄰接表元素屬性作為node的文本,鄰接表元素的孩子作為node的子節(jié)點(diǎn);同時(shí)設(shè)置node的tag值為指向鄰接表當(dāng)前元素的指針;
2)修改操作。在treenode中選擇一個(gè)node,將該node的值顯示于文本控件中供用戶進(jìn)行修改,并將修改后的值填寫(xiě)回treenode的node節(jié)點(diǎn),同時(shí)修改node節(jié)點(diǎn)的tag值所指向的鄰接表元素的相應(yīng)的屬性;
3)刪除操作。刪除treenode中選中的節(jié)點(diǎn)node,同時(shí)刪除node節(jié)點(diǎn)的tag值所指向的鄰接表元素的節(jié)點(diǎn)及其孩子節(jié)點(diǎn);
4)添加操作。設(shè)用戶需要添加的信息為attr:value格式,則,若value不是以“@”開(kāi)始的字符串,那么attr:value直接添加于treenode控件中,使其為當(dāng)前選中node的孩子節(jié)點(diǎn),同時(shí)在node節(jié)點(diǎn)的tag值所指向的鄰接表元素中增加value屬性值;若value是以“@k”開(kāi)始的字符串,那么需判定k的范圍,若k<=m即表示k是已經(jīng)存在的節(jié)點(diǎn),則在treenode中找到編號(hào)為k的node1節(jié)點(diǎn),并將node1節(jié)點(diǎn)為根的子樹(shù)添加到treenode控件中,使node1作為當(dāng)前選中節(jié)點(diǎn)node的孩子節(jié)點(diǎn),同時(shí)在node節(jié)點(diǎn)的tag值節(jié)點(diǎn)所指向的鄰接表元素中增加“@k”屬性即可;若k>m即表示k是新添加的節(jié)點(diǎn),則構(gòu)造一個(gè)新的node1節(jié)點(diǎn),并使其為當(dāng)前選中node的孩子節(jié)點(diǎn),同時(shí)在node的tag值所指向的鄰接表元素中增加屬性值“@k”并在鄰接表的最后增加一個(gè)編號(hào)為k的元素;
5)查找操作。根據(jù)用戶提供的關(guān)鍵字,在treenode的各個(gè)節(jié)點(diǎn)中進(jìn)行模糊匹配,若匹配成功則突出顯示該節(jié)點(diǎn);
最后,將鄰接表形式的抽象語(yǔ)法樹(shù)可視化,具體方法如下:
1)廣度優(yōu)先遍歷鄰接表形式的抽象語(yǔ)法樹(shù),根據(jù)語(yǔ)法樹(shù)的節(jié)點(diǎn)信息及節(jié)點(diǎn)之間的關(guān)系,構(gòu)造如下形式的ast.dot文檔:
digraphast{
nodesep=1.0
node[shape=record]
structinfolist
edgeinfolist
}
其中,
structinfolist=structinfo*
structinfo=structname[label=”attrinfo”]
structname=string
attrinfo=<fn>attr(|<fk>attr)*
attr=string
edgeinfolist=edgeinfo*
edgeinfo=structname1:fn->structname2:fk
生成ast.dot文檔的具體方法是:遍歷抽象語(yǔ)法樹(shù)過(guò)程中當(dāng)訪問(wèn)一個(gè)節(jié)點(diǎn)時(shí),首先,以struct加節(jié)點(diǎn)編號(hào)structk的形式建立.dot的一個(gè)名字structname,節(jié)點(diǎn)的所有屬性value按照<f0>value0|<f1>value1|…|<fn>valuen的形式建立structname的attrinfo值;其次,對(duì)當(dāng)前節(jié)點(diǎn)的每個(gè)孩子節(jié)點(diǎn)建立一個(gè)edgeinfo,即structname1:fn->structname2:fk,其中,structname1為當(dāng)前節(jié)點(diǎn)的名字,fn為其屬性編號(hào),structname2為孩子節(jié)點(diǎn)的名字,fk為孩子節(jié)點(diǎn)的屬性編號(hào);按照以上方法廣度遍歷抽象語(yǔ)法樹(shù)的每個(gè)節(jié)點(diǎn),最終形成.dot格式的文檔;
2)調(diào)用圖形可視化工具graphviz生成抽象語(yǔ)法樹(shù)的圖片文件。命令格式為:“dot–tjpgast.dot–oast.jpg”;
打開(kāi)ast.jpg文件,實(shí)現(xiàn)圖片的瀏覽、縮放、移動(dòng)等功能;
步驟四、程序分析結(jié)果可視化。其特征在于程序分析結(jié)果可視化方法具體包括:
1)構(gòu)造控制流圖:新建一個(gè)基本塊,按照廣度優(yōu)先遍歷鄰接表形式的抽象語(yǔ)法樹(shù),針對(duì)語(yǔ)法樹(shù)中的各類節(jié)點(diǎn)分別處理:
a.“function_decl”節(jié)點(diǎn)與“bind_expr”節(jié)點(diǎn)查找其“body”字段指向的孩子節(jié)點(diǎn)繼續(xù)遍歷;
b.“statement_list”節(jié)點(diǎn)查找其所有孩子節(jié)點(diǎn),依次遞歸遍歷每個(gè)孩子節(jié)點(diǎn)為根的子樹(shù);
c.“cond_expr”節(jié)點(diǎn),首先將分支條件“op0”字段的信息加入到當(dāng)前基本快,并結(jié)束當(dāng)前基本塊b1,其次分別遞歸遍歷then分支“op1”字段和else分支“op2”字段所指向的孩子節(jié)點(diǎn)為根的子樹(shù),分別形成以b2和b3為根的子圖,最后設(shè)置基本塊b1的后繼節(jié)點(diǎn)分別為b2和b3;
d.“goto_expr”節(jié)點(diǎn),結(jié)束當(dāng)前基本塊,在label棧中查找該跳轉(zhuǎn)語(yǔ)句的目標(biāo)標(biāo)號(hào)所在的基本塊是否已經(jīng)創(chuàng)建,若已創(chuàng)建則設(shè)置當(dāng)前基本塊的孩子節(jié)點(diǎn)為目標(biāo)標(biāo)號(hào)所在基本塊,否則將該基本塊信息保存如goto棧;
e.“l(fā)abel_expe”節(jié)點(diǎn),結(jié)束當(dāng)前基本塊,新建一個(gè)基本塊,設(shè)置當(dāng)前基本塊的后繼節(jié)點(diǎn)為新建的基本塊,在goto棧中查找是否存在需要跳轉(zhuǎn)到新建基本塊的語(yǔ)句,若找到,則將找到的基本塊的后繼設(shè)置為新建基本塊,否則將新建塊的信息保存入label棧;
f.其它節(jié)點(diǎn),將語(yǔ)句信息加入到當(dāng)前基本塊;
2)構(gòu)造控制依賴圖:創(chuàng)建控制依賴圖的根節(jié)點(diǎn),廣度優(yōu)先遍歷抽象語(yǔ)法樹(shù),針對(duì)語(yǔ)法樹(shù)中不同節(jié)點(diǎn)分別處理:
a.“function_decl”節(jié)點(diǎn),創(chuàng)建函數(shù)信息為內(nèi)容的新節(jié)點(diǎn)并使其成為根節(jié)點(diǎn)的孩子節(jié)點(diǎn),將新建節(jié)點(diǎn)設(shè)為當(dāng)前節(jié)點(diǎn),繼續(xù)遍歷以“body”字段所指向的節(jié)點(diǎn)為根的抽象語(yǔ)法樹(shù);
b.“bind_expr”節(jié)點(diǎn),創(chuàng)建分程序信息為內(nèi)容的新節(jié)點(diǎn)并使其成為當(dāng)前節(jié)點(diǎn)的孩子節(jié)點(diǎn),將新建節(jié)點(diǎn)設(shè)為當(dāng)前節(jié)點(diǎn),繼續(xù)遍歷以“body”字段所指向的節(jié)點(diǎn)為根的抽象語(yǔ)法樹(shù);
c.“statement_list”節(jié)點(diǎn),創(chuàng)建語(yǔ)句列表信息為內(nèi)容的新節(jié)點(diǎn)并使其成為當(dāng)前節(jié)點(diǎn)的孩子節(jié)點(diǎn),將新建節(jié)點(diǎn)設(shè)為當(dāng)前節(jié)點(diǎn),遞歸遍歷所有字段的孩子節(jié)點(diǎn)為根的子樹(shù);
d.“cond_expr”節(jié)點(diǎn),創(chuàng)建分支語(yǔ)句op0字段為內(nèi)容的新節(jié)點(diǎn)并使其成為當(dāng)前節(jié)點(diǎn)的孩子節(jié)點(diǎn),將新建節(jié)點(diǎn)設(shè)為當(dāng)前節(jié)點(diǎn),分別遞歸遍歷op1和op2字段所指向的孩子節(jié)點(diǎn)為根的子樹(shù);
e.其它節(jié)點(diǎn),創(chuàng)建相應(yīng)的新節(jié)點(diǎn)并使其成為當(dāng)前節(jié)點(diǎn)的孩子節(jié)點(diǎn);
3)廣度優(yōu)先遍歷控制流圖(控制依賴圖),依據(jù)控制流圖中節(jié)點(diǎn)信息和節(jié)點(diǎn)之間的關(guān)系,生成如下形式的cfg.dot文檔:
digraphast{
nodesep=1.0
start[label=”entry”,shape=box]
nodeinfolist
edgeinfolist
}
其中,
nodeinfolist=nodeinfo*
nodeinfo=nodename[label=”attrinfo”,shape=box]
edgeinfolist=edgeinfo*
edgeinfo=nodenamei->nodenamej([label=”t|f”])?
生成cfg.dot文檔的具體方法是:遍歷控制流圖過(guò)程中當(dāng)訪問(wèn)一個(gè)節(jié)點(diǎn)時(shí),首先,以node加節(jié)點(diǎn)編號(hào)nodek的形式建立cfg.dot的一個(gè)名字nodename,節(jié)點(diǎn)的所有屬性value按照“value0\nvalue1\n…\nvaluek”的形式建立nodename的attrinfo值。其次,對(duì)當(dāng)前節(jié)點(diǎn)的每個(gè)孩子節(jié)點(diǎn)建立一個(gè)edgeinfo,若當(dāng)前節(jié)點(diǎn)只有一個(gè)孩子節(jié)點(diǎn),則建立如下形式的edgeinfo,即nodename1->nodename2,其中,nodename1為當(dāng)前節(jié)點(diǎn)的名字,nodename2為孩子節(jié)點(diǎn)的名字;若當(dāng)前節(jié)點(diǎn)有兩個(gè)孩子節(jié)點(diǎn),則對(duì)真分支節(jié)點(diǎn)建立如下形式的edgeinfo,nodename1->nodename2[label=”t”],對(duì)假分支建立如下形式的edgeinfo,nodename1->nodename2[label=”f”]。按照以上方法廣度遍歷抽象語(yǔ)法樹(shù)的每個(gè)節(jié)點(diǎn),最終形成cfg.dot格式的文檔;
4)調(diào)用圖形可視化工具graphviz生成抽象語(yǔ)法樹(shù)的圖片文件。命令格式為:“dot–tjpgast.dot–oast.jpg”;
5)打開(kāi)ast.jpg文件,實(shí)現(xiàn)圖片的瀏覽、縮放、移動(dòng)等功能。
本發(fā)明提供了程序分析過(guò)程可視化軟件,包括:
輸入模塊,用于讀入待分析的源程序,
轉(zhuǎn)換模塊,用于將源程序轉(zhuǎn)換為中間表示,
標(biāo)準(zhǔn)化模塊,用于將中間表示規(guī)范化和化簡(jiǎn),
元級(jí)操作模塊,提供程序中間表示一級(jí)的各成分的增刪改查等操作,
圖形化展示分析結(jié)果模塊,用于圖像化展示程序分析的抽象語(yǔ)法樹(shù)、控制流圖、控制依賴圖。
進(jìn)一步地,所屬展示模塊具體包括:
圖形化輸出程序的抽象語(yǔ)法樹(shù),
圖形化輸出程序的控制流圖,
圖形化輸出程序的控制依賴圖。
由上可知,本發(fā)明方法和系統(tǒng)能夠直觀地展示程序分析的過(guò)程和分析結(jié)果。
附圖說(shuō)明
圖1為本發(fā)明所述的一種程序分析過(guò)程可視化方法及系統(tǒng)所采用的程序整體功能流程圖。
圖2為本發(fā)明所述的一種程序分析過(guò)程可視化方法及系統(tǒng)中的實(shí)施例一所揭示的輸入源程序。
圖3為本發(fā)明所述的一種程序分析過(guò)程可視化方法及系統(tǒng)中的實(shí)施例一所揭示的程序抽象語(yǔ)法樹(shù)。
圖4為本發(fā)明所述的一種程序分析過(guò)程可視化方法及系統(tǒng)中的實(shí)施例二所揭示的程序控制流圖。
具體實(shí)施方式
為使本發(fā)明的目的、技術(shù)方案、及優(yōu)點(diǎn)更加清楚明白,下面結(jié)合附圖對(duì)本發(fā)明涉及的一種服務(wù)功能授權(quán)的方法及系統(tǒng)的具體實(shí)施實(shí)例進(jìn)行進(jìn)一步詳細(xì)描述。
本發(fā)明所述的程序過(guò)程可視化方法的基本原理為:
參見(jiàn)圖1,本發(fā)明所采用的程序過(guò)程可視化方法由四個(gè)模塊構(gòu)成,即程序轉(zhuǎn)換模塊、標(biāo)準(zhǔn)化模塊、元級(jí)操作模塊、分析結(jié)果可視化模塊;
程序轉(zhuǎn)換模塊:將輸入的源程序轉(zhuǎn)換為中間表示;
標(biāo)準(zhǔn)化模塊:刪除中間表示中的與數(shù)據(jù)流、控制流無(wú)關(guān)的信息;
元級(jí)操作模塊:在抽象語(yǔ)法樹(shù)上對(duì)程序的各個(gè)語(yǔ)法成分進(jìn)行增刪改查等操作;
分析結(jié)果可視化模塊:構(gòu)造程序的控制流圖、控制依賴圖,并以圖片的形式直觀地展示。
本發(fā)明所述的一種程序分析過(guò)程可視化方法的步驟如下:
步驟一、程序轉(zhuǎn)換為中間表示。其特征在于:使用開(kāi)源編譯器gcc攜帶參數(shù)-fdump-translation-unit,對(duì)源程序進(jìn)行詞法分析、語(yǔ)法分析,并生成程序的以節(jié)點(diǎn)為單位的中間表示;
步驟二、中間表示標(biāo)準(zhǔn)化處理。其特征在于中間表示的標(biāo)準(zhǔn)化處理方法:
將程序的中間表示規(guī)范化,包括規(guī)范每個(gè)節(jié)點(diǎn)成一行、刪除節(jié)點(diǎn)各個(gè)字段內(nèi)部多余的空格;
消除中間表示里與數(shù)據(jù)流、控制流無(wú)關(guān)的信息。首先將srcp字段值為源程序文件名的節(jié)點(diǎn)標(biāo)注為有用節(jié)點(diǎn),將srcp字段為其它值的節(jié)點(diǎn)標(biāo)注為無(wú)用節(jié)點(diǎn),其它節(jié)點(diǎn)為待定節(jié)點(diǎn);其次將有用節(jié)點(diǎn)的標(biāo)為待定的節(jié)點(diǎn)標(biāo)記為有用節(jié)點(diǎn),將無(wú)用節(jié)點(diǎn)的標(biāo)為待定的節(jié)點(diǎn)標(biāo)記為無(wú)用節(jié)點(diǎn),將沖突節(jié)點(diǎn)(父節(jié)點(diǎn)既有有用節(jié)點(diǎn)又有無(wú)用節(jié)點(diǎn))標(biāo)記為有用節(jié)點(diǎn);最后刪除無(wú)用節(jié)點(diǎn),并刪除每個(gè)節(jié)點(diǎn)中的srcp、algn、type字段及指向節(jié)點(diǎn)已被刪除的字段;
步驟三、中間表示的元級(jí)操作。其特征在于元級(jí)操作方法:在中間表示一級(jí)上對(duì)程序中的各種語(yǔ)法成分進(jìn)行增刪改查操作;
首先,將程序的中間表示轉(zhuǎn)換為鄰接表形式的抽象語(yǔ)法樹(shù)ast,其方法如下:
設(shè)程序的原始中間表示有n個(gè)節(jié)點(diǎn)信息,經(jīng)過(guò)標(biāo)準(zhǔn)化處理后剩余m個(gè)節(jié)點(diǎn),則將m個(gè)中間表示節(jié)點(diǎn)分別轉(zhuǎn)換為鄰接表的m個(gè)元素:
1)將字符串形式的中間表示節(jié)點(diǎn)拆分成“@kiname_type{attr:value}+”格式的子串,其中1<=ki<=n,1<=i<=m;
2)將非連續(xù)編號(hào)的m個(gè)ki映射為鄰接表的m個(gè)連續(xù)編號(hào),即建立編號(hào)映射表map={k1->1,k2->2,......km->m};
3)取map(ki)作為鄰接表元素的編號(hào);name_type作為鄰接表元素的類型;若value是“@kj”形式的子串,其中1<=kj<=n,1<=j<=m,則將編號(hào)為map(kj)的鄰接表元素作為當(dāng)前元素的孩子節(jié)點(diǎn),否則value直接作為當(dāng)前鄰接表元素的一個(gè)屬性值;
其次,在鄰接表上對(duì)程序進(jìn)行元級(jí)操作,其方法如下:
1)建立鄰接表形式的抽象語(yǔ)法樹(shù)與.net中的樹(shù)控件treenode之間的映射關(guān)系,將抽象語(yǔ)法樹(shù)以便于操作的控件的形式呈現(xiàn)給用戶。映射關(guān)系建立規(guī)則為:鄰接表的一個(gè)元素建立treenode中的一個(gè)node節(jié)點(diǎn),鄰接表元素屬性作為node的文本,鄰接表元素的孩子作為node的子節(jié)點(diǎn);同時(shí)設(shè)置node的tag值為指向鄰接表當(dāng)前元素的指針;
2)修改操作。在treenode中選擇一個(gè)node,將該node的值顯示于文本控件中供用戶進(jìn)行修改,并將修改后的值填寫(xiě)回treenode的node節(jié)點(diǎn),同時(shí)修改node節(jié)點(diǎn)的tag值所指向的鄰接表元素的相應(yīng)的屬性;
3)刪除操作。刪除treenode中選中的節(jié)點(diǎn)node,同時(shí)刪除node節(jié)點(diǎn)的tag值所指向的鄰接表元素的節(jié)點(diǎn)及其孩子節(jié)點(diǎn);
4)添加操作。設(shè)用戶需要添加的信息為attr:value格式,則,若value不是以“@”開(kāi)始的字符串,那么attr:value直接添加于treenode控件中,使其為當(dāng)前選中node的孩子節(jié)點(diǎn),同時(shí)在node節(jié)點(diǎn)的tag值所指向的鄰接表元素中增加value屬性值;若value是以“@k”開(kāi)始的字符串,那么需判定k的范圍,若k<=m即表示k是已經(jīng)存在的節(jié)點(diǎn),則在treenode中找到編號(hào)為k的node1節(jié)點(diǎn),并將node1節(jié)點(diǎn)為根的子樹(shù)添加到treenode控件中,使node1作為當(dāng)前選中節(jié)點(diǎn)node的孩子節(jié)點(diǎn),同時(shí)在node節(jié)點(diǎn)的tag值節(jié)點(diǎn)所指向的鄰接表元素中增加“@k”屬性即可;若k>m即表示k是新添加的節(jié)點(diǎn),則構(gòu)造一個(gè)新的node1節(jié)點(diǎn),并使其為當(dāng)前選中node的孩子節(jié)點(diǎn),同時(shí)在node的tag值所指向的鄰接表元素中增加屬性值“@k”并在鄰接表的最后增加一個(gè)編號(hào)為k的元素;
5)查找操作。根據(jù)用戶提供的關(guān)鍵字,在treenode的各個(gè)節(jié)點(diǎn)中進(jìn)行模糊匹配,若匹配成功則突出顯示該節(jié)點(diǎn);
最后,將鄰接表形式的抽象語(yǔ)法樹(shù)可視化,具體方法如下:
1)廣度優(yōu)先遍歷鄰接表形式的抽象語(yǔ)法樹(shù),根據(jù)語(yǔ)法樹(shù)的節(jié)點(diǎn)信息及節(jié)點(diǎn)之間的關(guān)系,構(gòu)造如下形式的ast.dot文檔:
digraphast{
nodesep=1.0
node[shape=record]
structinfolist
edgeinfolist
}
其中,
structinfolist=structinfo*
structinfo=structname[label=”attrinfo”]
structname=string
attrinfo=<fn>attr(|<fk>attr)*
attr=string
edgeinfolist=edgeinfo*
edgeinfo=structname1:fn->structname2:fk
生成ast.dot文檔的具體方法是:遍歷抽象語(yǔ)法樹(shù)過(guò)程中當(dāng)訪問(wèn)一個(gè)節(jié)點(diǎn)時(shí),首先,以struct加節(jié)點(diǎn)編號(hào)structk的形式建立.dot的一個(gè)名字structname,節(jié)點(diǎn)的所有屬性value按照<f0>value0|<f1>value1|…|<fn>valuen的形式建立structname的attrinfo值;其次,對(duì)當(dāng)前節(jié)點(diǎn)的每個(gè)孩子節(jié)點(diǎn)建立一個(gè)edgeinfo,即structname1:fn->structname2:fk,其中,structname1為當(dāng)前節(jié)點(diǎn)的名字,fn為其屬性編號(hào),structname2為孩子節(jié)點(diǎn)的名字,fk為孩子節(jié)點(diǎn)的屬性編號(hào);按照以上方法廣度遍歷抽象語(yǔ)法樹(shù)的每個(gè)節(jié)點(diǎn),最終形成.dot格式的文檔;
2)調(diào)用圖形可視化工具graphviz生成抽象語(yǔ)法樹(shù)的圖片文件。命令格式為:“dot–tjpgast.dot–oast.jpg”;
打開(kāi)ast.jpg文件,實(shí)現(xiàn)圖片的瀏覽、縮放、移動(dòng)等功能;
步驟四、程序分析結(jié)果可視化。其特征在于程序分析結(jié)果可視化方法具體包括:
1)構(gòu)造控制流圖:新建一個(gè)基本塊,按照廣度優(yōu)先遍歷鄰接表形式的抽象語(yǔ)法樹(shù),針對(duì)語(yǔ)法樹(shù)中的各類節(jié)點(diǎn)分別處理:
a.“function_decl”節(jié)點(diǎn)與“bind_expr”節(jié)點(diǎn)查找其“body”字段指向的孩子節(jié)點(diǎn)繼續(xù)遍歷;
b.“statement_list”節(jié)點(diǎn)查找其所有孩子節(jié)點(diǎn),依次遞歸遍歷每個(gè)孩子節(jié)點(diǎn)為根的子樹(shù);
c.“cond_expr”節(jié)點(diǎn),首先將分支條件“op0”字段的信息加入到當(dāng)前基本快,并結(jié)束當(dāng)前基本塊b1,其次分別遞歸遍歷then分支“op1”字段和else分支“op2”字段所指向的孩子節(jié)點(diǎn)為根的子樹(shù),分別形成以b2和b3為根的子圖,最后設(shè)置基本塊b1的后繼節(jié)點(diǎn)分別為b2和b3;
d.“goto_expr”節(jié)點(diǎn),結(jié)束當(dāng)前基本塊,在label棧中查找該跳轉(zhuǎn)語(yǔ)句的目標(biāo)標(biāo)號(hào)所在的基本塊是否已經(jīng)創(chuàng)建,若已創(chuàng)建則設(shè)置當(dāng)前基本塊的孩子節(jié)點(diǎn)為目標(biāo)標(biāo)號(hào)所在基本塊,否則將該基本塊信息保存如goto棧;
e.“l(fā)abel_expe”節(jié)點(diǎn),結(jié)束當(dāng)前基本塊,新建一個(gè)基本塊,設(shè)置當(dāng)前基本塊的后繼節(jié)點(diǎn)為新建的基本塊,在goto棧中查找是否存在需要跳轉(zhuǎn)到新建基本塊的語(yǔ)句,若找到,則將找到的基本塊的后繼設(shè)置為新建基本塊,否則將新建塊的信息保存入label棧;
f.其它節(jié)點(diǎn),將語(yǔ)句信息加入到當(dāng)前基本塊;
2)構(gòu)造控制依賴圖:創(chuàng)建控制依賴圖的根節(jié)點(diǎn),廣度優(yōu)先遍歷抽象語(yǔ)法樹(shù),針對(duì)語(yǔ)法樹(shù)中不同節(jié)點(diǎn)分別處理:
a.“function_decl”節(jié)點(diǎn),創(chuàng)建函數(shù)信息為內(nèi)容的新節(jié)點(diǎn)并使其成為根節(jié)點(diǎn)的孩子節(jié)點(diǎn),將新建節(jié)點(diǎn)設(shè)為當(dāng)前節(jié)點(diǎn),繼續(xù)遍歷以“body”字段所指向的節(jié)點(diǎn)為根的抽象語(yǔ)法樹(shù);
b.“bind_expr”節(jié)點(diǎn),創(chuàng)建分程序信息為內(nèi)容的新節(jié)點(diǎn)并使其成為當(dāng)前節(jié)點(diǎn)的孩子節(jié)點(diǎn),將新建節(jié)點(diǎn)設(shè)為當(dāng)前節(jié)點(diǎn),繼續(xù)遍歷以“body”字段所指向的節(jié)點(diǎn)為根的抽象語(yǔ)法樹(shù);
c.“statement_list”節(jié)點(diǎn),創(chuàng)建語(yǔ)句列表信息為內(nèi)容的新節(jié)點(diǎn)并使其成為當(dāng)前節(jié)點(diǎn)的孩子節(jié)點(diǎn),將新建節(jié)點(diǎn)設(shè)為當(dāng)前節(jié)點(diǎn),遞歸遍歷所有字段的孩子節(jié)點(diǎn)為根的子樹(shù);
d.“cond_expr”節(jié)點(diǎn),創(chuàng)建分支語(yǔ)句op0字段為內(nèi)容的新節(jié)點(diǎn)并使其成為當(dāng)前節(jié)點(diǎn)的孩子節(jié)點(diǎn),將新建節(jié)點(diǎn)設(shè)為當(dāng)前節(jié)點(diǎn),分別遞歸遍歷op1和op2字段所指向的孩子節(jié)點(diǎn)為根的子樹(shù);
e.其它節(jié)點(diǎn),創(chuàng)建相應(yīng)的新節(jié)點(diǎn)并使其成為當(dāng)前節(jié)點(diǎn)的孩子節(jié)點(diǎn);
3)廣度優(yōu)先遍歷控制流圖(控制依賴圖),依據(jù)控制流圖中節(jié)點(diǎn)信息和節(jié)點(diǎn)之間的關(guān)系,生成如下形式的cfg.dot文檔:
digraphast{
nodesep=1.0
start[label=”entry”,shape=box]
nodeinfolist
edgeinfolist
}
其中,
nodeinfolist=nodeinfo*
nodeinfo=nodename[label=”attrinfo”,shape=box]
edgeinfolist=edgeinfo*
edgeinfo=nodenamei->nodenamej([label=”t|f”])?
生成cfg.dot文檔的具體方法是:遍歷控制流圖過(guò)程中當(dāng)訪問(wèn)一個(gè)節(jié)點(diǎn)時(shí),首先,以node加節(jié)點(diǎn)編號(hào)nodek的形式建立cfg.dot的一個(gè)名字nodename,節(jié)點(diǎn)的所有屬性value按照“value0\nvalue1\n…\nvaluek”的形式建立nodename的attrinfo值。其次,對(duì)當(dāng)前節(jié)點(diǎn)的每個(gè)孩子節(jié)點(diǎn)建立一個(gè)edgeinfo,若當(dāng)前節(jié)點(diǎn)只有一個(gè)孩子節(jié)點(diǎn),則建立如下形式的edgeinfo,即nodename1->nodename2,其中,nodename1為當(dāng)前節(jié)點(diǎn)的名字,nodename2為孩子節(jié)點(diǎn)的名字;若當(dāng)前節(jié)點(diǎn)有兩個(gè)孩子節(jié)點(diǎn),則對(duì)真分支節(jié)點(diǎn)建立如下形式的edgeinfo,nodename1->nodename2[label=”t”],對(duì)假分支建立如下形式的edgeinfo,nodename1->nodename2[label=”f”]。按照以上方法廣度遍歷抽象語(yǔ)法樹(shù)的每個(gè)節(jié)點(diǎn),最終形成cfg.dot格式的文檔;
4)調(diào)用圖形可視化工具graphviz生成抽象語(yǔ)法樹(shù)的圖片文件。命令格式為:“dot–tjpgast.dot–oast.jpg”;
5)打開(kāi)ast.jpg文件,實(shí)現(xiàn)圖片的瀏覽、縮放、移動(dòng)等功能。
下面提供兩個(gè)具體實(shí)施方式對(duì)本發(fā)明所述的程序分析過(guò)程可視化方法及系統(tǒng)的具體過(guò)程進(jìn)行說(shuō)明:
一、本實(shí)施例為構(gòu)造程序抽象語(yǔ)法樹(shù)。本實(shí)施例中,我們對(duì)一段c程序進(jìn)行元級(jí)操作并輸出其抽象語(yǔ)法樹(shù),具體過(guò)程如下:
步驟一、輸入圖2所示的源程序,將其轉(zhuǎn)換為中間表示;
步驟二、將中間表示規(guī)范化并化簡(jiǎn);
步驟三、構(gòu)造抽象語(yǔ)法樹(shù),并在其上進(jìn)行所需的元級(jí)操作;
步驟四、圖形化輸出抽象語(yǔ)法樹(shù),參見(jiàn)圖3;
二、本實(shí)施例為構(gòu)造控制流圖。本實(shí)施例中,我們構(gòu)造了一段c程序的控制流圖,具體過(guò)程如下:
步驟一、輸入圖2所示的源程序,將其轉(zhuǎn)換為中間表示;
步驟二、將中間表示規(guī)范化并化簡(jiǎn);
步驟三、構(gòu)造程序的抽象語(yǔ)法樹(shù);
步驟四、構(gòu)造程序的控制流圖并圖形化輸出控制流圖,參見(jiàn)圖4;
以上具體實(shí)施方式僅用于說(shuō)明本發(fā)明,而非用于限定本發(fā)明。