这个问题我已经想搞清楚很久了,不得不说,很多开发工具(或者说开源项目)的人,脑子都是一团浆糊,虽然标榜自己可用于科研,但是完全不知道科研人员的需求在哪,写出来的文档也是乱七八糟。
按照以前的Joern的文档,我根本没搞清楚怎么生成PDG,现在算是清楚了:https://docs.joern.io/exporting/
我们以一个别人论文里的例子来说明,例如我要生成下面这个Example.c文件的PDG:
int main(int argc, char **argv)
{
char *items[] = {"boat", "car", "truck", "train"};
int index = Untrusted();
printf("You selected %s\n", items[index-1]);
int upbound = sizeof(items) / sizeof(items[0]);
printf("Last item %s\n", items[upbound - 1]);
}
这个文件是没法编译的,但是通过island grammar,Joern是可以分析它的,在安装好了Joern之后,我们运行:
./joern-parse Example.c
./joern-export --repr pdg --out Example
就可以生成一个Example的目录,并且在目录下面有0-pdg.dot,1-pdg.dot,2-pdg.dot这些文件,我们一般只关心第一个即可,可以看看这个文件长什么样:
digraph main {
"1000100" [label = "(METHOD,main)" ]
"1000135" [label = "(METHOD_RETURN,int)" ]
"1000101" [label = "(PARAM,int argc)" ]
"1000102" [label = "(PARAM,char **argv)" ]
"1000105" [label = "(.assignment,*items[] = {\"boat\", \"car\", \"truck\", \"train\"})" ]
"1000108" [label = "(.assignment,index = Untrusted())" ]
"1000111" [label = "(printf,printf(\"You selected %s\n\", items[index-1]))" ]
"1000115" [label = "(.subtraction,index-1)" ]
"1000119" [label = "(.assignment,upbound = sizeof(items) / sizeof(items[0]))" ]
"1000121" [label = "(.division,sizeof(items) / sizeof(items[0]))" ]
"1000122" [label = "(.sizeOf,sizeof(items))" ]
"1000124" [label = "(.sizeOf,sizeof(items[0]))" ]
"1000128" [label = "(printf,printf(\"Last item %s\n\", items[upbound - 1]))" ]
"1000132" [label = "(.subtraction,upbound - 1)" ]
"1000119" -> "1000135" [ label = "DDG: sizeof(items) / sizeof(items[0])"]
"1000128" -> "1000135" [ label = "DDG: items[upbound - 1]"]
"1000102" -> "1000135" [ label = "DDG: argv"]
"1000124" -> "1000135" [ label = "DDG: items[0]"]
"1000101" -> "1000135" [ label = "DDG: argc"]
"1000111" -> "1000135" [ label = "DDG: printf(\"You selected %s\n\", items[index-1])"]
"1000122" -> "1000135" [ label = "DDG: items"]
"1000111" -> "1000135" [ label = "DDG: items[index-1]"]
"1000128" -> "1000135" [ label = "DDG: printf(\"Last item %s\n\", items[upbound - 1])"]
"1000108" -> "1000135" [ label = "DDG: Untrusted()"]
"1000132" -> "1000135" [ label = "DDG: upbound"]
"1000115" -> "1000135" [ label = "DDG: index"]
"1000100" -> "1000101" [ label = "DDG: "]
"1000100" -> "1000102" [ label = "DDG: "]
"1000100" -> "1000105" [ label = "DDG: "]
"1000100" -> "1000108" [ label = "DDG: "]
"1000100" -> "1000111" [ label = "DDG: "]
"1000105" -> "1000111" [ label = "DDG: items"]
"1000108" -> "1000115" [ label = "DDG: index"]
"1000100" -> "1000115" [ label = "DDG: "]
"1000100" -> "1000119" [ label = "DDG: "]
"1000100" -> "1000121" [ label = "DDG: "]
"1000100" -> "1000122" [ label = "DDG: "]
"1000100" -> "1000128" [ label = "DDG: "]
"1000119" -> "1000132" [ label = "DDG: upbound"]
"1000100" -> "1000132" [ label = "DDG: "]
}
如果我们运行:
dot -Tpng 0-pdg.dot -o 0-pdg.png
就可以生成下面这个图:
可以很明显地看到,这个图并不是以语句为节点单位的,而是更细粒度的类似于AST节点的node。但是,往往我们在分析源码的时候,需要和某一行对应起来(例如Diff是以一行作为单位的),那怎么办呢?抱歉,Joern的文档是不会给我们答案的。例如这里有人也提了这个问题:https://gitter.im/joern-code-analyzer/community
呵呵呵,但是并没有人回复他。所以得自己想想办法。
按照这里的介绍,我们是可以query所生成的CPG(Code Property Graph)的所有信息的:https://docs.joern.io/quickstart#querying-the-code-property-graph
例如我们可以通过:
cpg.method.name.l
来返回所分析代码中的所有function name,按道理说,看上面的0-pdg.dot文件,每一个节点都有一个唯一的编号,那我们应该能把其行号输出出来:
最方便起见,我们可以用:
cpg.all.l
可以看到是包含所有的节点行号的,但是似乎不太好分析,看到这里介绍:https://docs.joern.io/cpgql/reference-card#execution-directives
除了用.l之外,我们可以输出成Json,这样就好分析了(顺便吐槽一下这个.l,你前面都没简写,后面不能用个.list吗,非得用个.l,让人和.1傻傻分不清):
cpg.all.toJsonPretty |> "Json.txt"
如果我们要批量分析很多个源码文件呢,那显然用这种interactive的方式就不行了,我们需要借助于:https://docs.joern.io/interpreter
例如我们保存一个test.sc文件:
@main def exec() = {
loadCpg("cpg.bin")
cpg.all.toJsonPretty |> "Temp.json"
}
然后运行:
./joern --script test.sc
就可以将Json文件输出了:
[
{
"overlays":[
"semanticcpg",
"dataflowOss"
],
"version":"0.1",
"language":"C",
"_label":"META_DATA",
"id":1
},
{
"name":"",
"fullName":"",
"id":2,
"_label":"NAMESPACE_BLOCK",
"order":1,
"filename":""
},
{
"name":"char *",
"fullName":"char *",
"typeDeclFullName":"char *",
"id":100,
"_label":"TYPE"
},
{
"name":"char * *",
"fullName":"char * *",
"typeDeclFullName":"char * *",
"id":101,
"_label":"TYPE"
},
{
"name":"char * [ ]",
"fullName":"char * [ ]",
"typeDeclFullName":"char * [ ]",
"id":102,
"_label":"TYPE"
},
{
"name":"int",
"fullName":"int",
"typeDeclFullName":"int",
"id":103,
"_label":"TYPE"
},
{
"name":"void",
"fullName":"void",
"typeDeclFullName":"void",
"id":104,
"_label":"TYPE"
},
{
"name":"",
"fullName":"/home/yu/bin/joern/Example.c:",
"id":1000099,
"_label":"NAMESPACE_BLOCK",
"order":1,
"filename":"/home/yu/bin/joern/Example.c"
},
{
"name":"main",
"astParentFullName":"",
"columnNumberEnd":0,
"fullName":"main",
"signature":"int main (int,char * *)",
"astParentType":"",
"columnNumber":0,
"lineNumberEnd":8,
"_label":"METHOD",
"code":"int main (int argc,char **argv)",
"isExternal":false,
"lineNumber":1,
"id":1000100,
"order":1,
"filename":"/home/yu/bin/joern/Example.c"
},
{
"name":"argc",
"evaluationStrategy":"BY_VALUE",
"code":"int argc",
"typeFullName":"int",
"columnNumber":9,
"order":1,
"_label":"METHOD_PARAMETER_IN",
"lineNumber":1,
"id":1000101
},
{
"name":"argv",
"evaluationStrategy":"BY_VALUE",
"code":"char **argv",
"typeFullName":"char * *",
"columnNumber":19,
"order":2,
"_label":"METHOD_PARAMETER_IN",
"lineNumber":1,
"id":1000102
},
{
"code":"",
"typeFullName":"void",
"columnNumber":0,
"order":3,
"_label":"BLOCK",
"argumentIndex":3,
"lineNumber":2,
"id":1000103
},
{
"name":"items",
"typeFullName":"char * [ ]",
"order":1,
"_label":"LOCAL",
"code":"items",
"id":1000104
},
{
"dispatchType":"STATIC_DISPATCH",
"name":".assignment",
"signature":"TODO",
"code":"*items[] = {\"boat\", \"car\", \"truck\", \"train\"}",
"typeFullName":"",
"columnNumber":9,
"order":2,
"methodFullName":".assignment",
"_label":"CALL",
"argumentIndex":2,
"lineNumber":3,
"id":1000105
},
{
"name":"items",
"code":"items",
"typeFullName":"char * [ ]",
"columnNumber":10,
"order":1,
"_label":"IDENTIFIER",
"argumentIndex":1,
"lineNumber":3,
"id":1000106
},
{
"name":"index",
"typeFullName":"int",
"order":3,
"_label":"LOCAL",
"code":"index",
"id":1000107
},
{
"dispatchType":"STATIC_DISPATCH",
"name":".assignment",
"signature":"TODO",
"code":"index = Untrusted()",
"typeFullName":"",
"columnNumber":8,
"order":4,
"methodFullName":".assignment",
"_label":"CALL",
"argumentIndex":4,
"lineNumber":4,
"id":1000108
},
{
"name":"index",
"code":"index",
"typeFullName":"int",
"columnNumber":8,
"order":1,
"_label":"IDENTIFIER",
"argumentIndex":1,
"lineNumber":4,
"id":1000109
},
{
"dispatchType":"STATIC_DISPATCH",
"name":"Untrusted",
"signature":"TODO",
"code":"Untrusted()",
"typeFullName":"",
"columnNumber":16,
"order":2,
"methodFullName":"Untrusted",
"_label":"CALL",
"argumentIndex":2,
"lineNumber":4,
"id":1000110
},
{
"dispatchType":"STATIC_DISPATCH",
"name":"printf",
"signature":"TODO",
"code":"printf(\"You selected %s\\n\", items[index-1])",
"typeFullName":"",
"columnNumber":4,
"order":5,
"methodFullName":"printf",
"_label":"CALL",
"argumentIndex":5,
"lineNumber":5,
"id":1000111
},
{
"code":"\"You selected %s\\n\"",
"typeFullName":"char *",
"columnNumber":11,
"order":1,
"_label":"LITERAL",
"argumentIndex":1,
"lineNumber":5,
"id":1000112
},
{
"dispatchType":"STATIC_DISPATCH",
"name":".indirectIndexAccess",
"signature":"TODO",
"code":"items[index-1]",
"typeFullName":"",
"columnNumber":32,
"order":2,
"methodFullName":".indirectIndexAccess",
"_label":"CALL",
"argumentIndex":2,
"lineNumber":5,
"id":1000113
},
{
"name":"items",
"code":"items",
"typeFullName":"char * [ ]",
"columnNumber":32,
"order":1,
"_label":"IDENTIFIER",
"argumentIndex":1,
"lineNumber":5,
"id":1000114
},
{
"dispatchType":"STATIC_DISPATCH",
"name":".subtraction",
"signature":"TODO",
"code":"index-1",
"typeFullName":"",
"columnNumber":38,
"order":2,
"methodFullName":".subtraction",
"_label":"CALL",
"argumentIndex":2,
"lineNumber":5,
"id":1000115
},
{
"name":"index",
"code":"index",
"typeFullName":"int",
"columnNumber":38,
"order":1,
"_label":"IDENTIFIER",
"argumentIndex":1,
"lineNumber":5,
"id":1000116
},
{
"code":"1",
"typeFullName":"int",
"columnNumber":44,
"order":2,
"_label":"LITERAL",
"argumentIndex":2,
"lineNumber":5,
"id":1000117
},
{
"name":"upbound",
"typeFullName":"int",
"order":6,
"_label":"LOCAL",
"code":"upbound",
"id":1000118
},
{
"dispatchType":"STATIC_DISPATCH",
"name":".assignment",
"signature":"TODO",
"code":"upbound = sizeof(items) / sizeof(items[0])",
"typeFullName":"",
"columnNumber":8,
"order":7,
"methodFullName":".assignment",
"_label":"CALL",
"argumentIndex":7,
"lineNumber":6,
"id":1000119
},
{
"name":"upbound",
"code":"upbound",
"typeFullName":"int",
"columnNumber":8,
"order":1,
"_label":"IDENTIFIER",
"argumentIndex":1,
"lineNumber":6,
"id":1000120
},
{
"dispatchType":"STATIC_DISPATCH",
"name":".division",
"signature":"TODO",
"code":"sizeof(items) / sizeof(items[0])",
"typeFullName":"",
"columnNumber":18,
"order":2,
"methodFullName":".division",
"_label":"CALL",
"argumentIndex":2,
"lineNumber":6,
"id":1000121
},
{
"dispatchType":"STATIC_DISPATCH",
"name":".sizeOf",
"signature":"TODO",
"code":"sizeof(items)",
"typeFullName":"",
"columnNumber":18,
"order":1,
"methodFullName":".sizeOf",
"_label":"CALL",
"argumentIndex":1,
"lineNumber":6,
"id":1000122
},
{
"name":"items",
"code":"items",
"typeFullName":"char * [ ]",
"columnNumber":25,
"order":1,
"_label":"IDENTIFIER",
"argumentIndex":1,
"lineNumber":6,
"id":1000123
},
{
"dispatchType":"STATIC_DISPATCH",
"name":".sizeOf",
"signature":"TODO",
"code":"sizeof(items[0])",
"typeFullName":"",
"columnNumber":34,
"order":2,
"methodFullName":".sizeOf",
"_label":"CALL",
"argumentIndex":2,
"lineNumber":6,
"id":1000124
},
{
"dispatchType":"STATIC_DISPATCH",
"name":".indirectIndexAccess",
"signature":"TODO",
"code":"items[0]",
"typeFullName":"",
"columnNumber":41,
"order":1,
"methodFullName":".indirectIndexAccess",
"_label":"CALL",
"argumentIndex":1,
"lineNumber":6,
"id":1000125
},
{
"name":"items",
"code":"items",
"typeFullName":"char * [ ]",
"columnNumber":41,
"order":1,
"_label":"IDENTIFIER",
"argumentIndex":1,
"lineNumber":6,
"id":1000126
},
{
"code":"0",
"typeFullName":"int",
"columnNumber":47,
"order":2,
"_label":"LITERAL",
"argumentIndex":2,
"lineNumber":6,
"id":1000127
},
{
"dispatchType":"STATIC_DISPATCH",
"name":"printf",
"signature":"TODO",
"code":"printf(\"Last item %s\\n\", items[upbound - 1])",
"typeFullName":"",
"columnNumber":4,
"order":8,
"methodFullName":"printf",
"_label":"CALL",
"argumentIndex":8,
"lineNumber":7,
"id":1000128
},
{
"code":"\"Last item %s\\n\"",
"typeFullName":"char *",
"columnNumber":11,
"order":1,
"_label":"LITERAL",
"argumentIndex":1,
"lineNumber":7,
"id":1000129
},
{
"dispatchType":"STATIC_DISPATCH",
"name":".indirectIndexAccess",
"signature":"TODO",
"code":"items[upbound - 1]",
"typeFullName":"",
"columnNumber":29,
"order":2,
"methodFullName":".indirectIndexAccess",
"_label":"CALL",
"argumentIndex":2,
"lineNumber":7,
"id":1000130
},
{
"name":"items",
"code":"items",
"typeFullName":"char * [ ]",
"columnNumber":29,
"order":1,
"_label":"IDENTIFIER",
"argumentIndex":1,
"lineNumber":7,
"id":1000131
},
{
"dispatchType":"STATIC_DISPATCH",
"name":".subtraction",
"signature":"TODO",
"code":"upbound - 1",
"typeFullName":"",
"columnNumber":35,
"order":2,
"methodFullName":".subtraction",
"_label":"CALL",
"argumentIndex":2,
"lineNumber":7,
"id":1000132
},
{
"name":"upbound",
"code":"upbound",
"typeFullName":"int",
"columnNumber":35,
"order":1,
"_label":"IDENTIFIER",
"argumentIndex":1,
"lineNumber":7,
"id":1000133
},
{
"code":"1",
"typeFullName":"int",
"columnNumber":45,
"order":2,
"_label":"LITERAL",
"argumentIndex":2,
"lineNumber":7,
"id":1000134
},
{
"evaluationStrategy":"BY_VALUE",
"code":"int",
"typeFullName":"int",
"columnNumber":0,
"order":4,
"_label":"METHOD_RETURN",
"lineNumber":1,
"id":1000135
},
{
"inheritsFromTypeFullName":[
],
"name":"char *",
"astParentFullName":"",
"fullName":"char *",
"astParentType":"NAMESPACE_BLOCK",
"isExternal":true,
"id":1000137,
"_label":"TYPE_DECL",
"order":-1,
"filename":""
},
{
"inheritsFromTypeFullName":[
],
"name":"char * *",
"astParentFullName":"",
"fullName":"char * *",
"astParentType":"NAMESPACE_BLOCK",
"isExternal":true,
"id":1000138,
"_label":"TYPE_DECL",
"order":-1,
"filename":""
},
{
"inheritsFromTypeFullName":[
],
"name":"char * [ ]",
"astParentFullName":"",
"fullName":"char * [ ]",
"astParentType":"NAMESPACE_BLOCK",
"isExternal":true,
"id":1000139,
"_label":"TYPE_DECL",
"order":-1,
"filename":""
},
{
"inheritsFromTypeFullName":[
],
"name":"int",
"astParentFullName":"",
"fullName":"int",
"astParentType":"NAMESPACE_BLOCK",
"isExternal":true,
"id":1000140,
"_label":"TYPE_DECL",
"order":-1,
"filename":""
},
{
"inheritsFromTypeFullName":[
],
"name":"void",
"astParentFullName":"",
"fullName":"void",
"astParentType":"NAMESPACE_BLOCK",
"isExternal":true,
"id":1000141,
"_label":"TYPE_DECL",
"order":-1,
"filename":""
},
{
"name":"Untrusted",
"astParentFullName":"",
"fullName":"Untrusted",
"signature":"TODO",
"astParentType":"NAMESPACE_BLOCK",
"_label":"METHOD",
"code":"",
"isExternal":true,
"id":1000142,
"order":0,
"filename":""
},
{
"evaluationStrategy":"BY_VALUE",
"code":"RET",
"typeFullName":"ANY",
"order":-1,
"_label":"METHOD_RETURN",
"id":1000143
},
{
"code":"",
"typeFullName":"ANY",
"order":1,
"_label":"BLOCK",
"argumentIndex":1,
"id":1000144
},
{
"name":".division",
"astParentFullName":"",
"fullName":".division",
"signature":"TODO",
"astParentType":"NAMESPACE_BLOCK",
"_label":"METHOD",
"code":"",
"isExternal":true,
"id":1000145,
"order":0,
"filename":""
},
{
"name":"p1",
"evaluationStrategy":"BY_VALUE",
"code":"p1",
"typeFullName":"ANY",
"order":1,
"_label":"METHOD_PARAMETER_IN",
"id":1000146
},
{
"name":"p2",
"evaluationStrategy":"BY_VALUE",
"code":"p2",
"typeFullName":"ANY",
"order":2,
"_label":"METHOD_PARAMETER_IN",
"id":1000147
},
{
"evaluationStrategy":"BY_VALUE",
"code":"RET",
"typeFullName":"ANY",
"order":-1,
"_label":"METHOD_RETURN",
"id":1000148
},
{
"code":"",
"typeFullName":"ANY",
"order":1,
"_label":"BLOCK",
"argumentIndex":1,
"id":1000149
},
{
"name":".subtraction",
"astParentFullName":"",
"fullName":".subtraction",
"signature":"TODO",
"astParentType":"NAMESPACE_BLOCK",
"_label":"METHOD",
"code":"",
"isExternal":true,
"id":1000150,
"order":0,
"filename":""
},
{
"name":"p1",
"evaluationStrategy":"BY_VALUE",
"code":"p1",
"typeFullName":"ANY",
"order":1,
"_label":"METHOD_PARAMETER_IN",
"id":1000151
},
{
"name":"p2",
"evaluationStrategy":"BY_VALUE",
"code":"p2",
"typeFullName":"ANY",
"order":2,
"_label":"METHOD_PARAMETER_IN",
"id":1000152
},
{
"evaluationStrategy":"BY_VALUE",
"code":"RET",
"typeFullName":"ANY",
"order":-1,
"_label":"METHOD_RETURN",
"id":1000153
},
{
"code":"",
"typeFullName":"ANY",
"order":1,
"_label":"BLOCK",
"argumentIndex":1,
"id":1000154
},
{
"name":".indirectIndexAccess",
"astParentFullName":"",
"fullName":".indirectIndexAccess",
"signature":"TODO",
"astParentType":"NAMESPACE_BLOCK",
"_label":"METHOD",
"code":"",
"isExternal":true,
"id":1000155,
"order":0,
"filename":""
},
{
"name":"p1",
"evaluationStrategy":"BY_VALUE",
"code":"p1",
"typeFullName":"ANY",
"order":1,
"_label":"METHOD_PARAMETER_IN",
"id":1000156
},
{
"name":"p2",
"evaluationStrategy":"BY_VALUE",
"code":"p2",
"typeFullName":"ANY",
"order":2,
"_label":"METHOD_PARAMETER_IN",
"id":1000157
},
{
"evaluationStrategy":"BY_VALUE",
"code":"RET",
"typeFullName":"ANY",
"order":-1,
"_label":"METHOD_RETURN",
"id":1000158
},
{
"code":"",
"typeFullName":"ANY",
"order":1,
"_label":"BLOCK",
"argumentIndex":1,
"id":1000159
},
{
"name":"printf",
"astParentFullName":"",
"fullName":"printf",
"signature":"TODO",
"astParentType":"NAMESPACE_BLOCK",
"_label":"METHOD",
"code":"",
"isExternal":true,
"id":1000160,
"order":0,
"filename":""
},
{
"name":"p1",
"evaluationStrategy":"BY_VALUE",
"code":"p1",
"typeFullName":"ANY",
"order":1,
"_label":"METHOD_PARAMETER_IN",
"id":1000161
},
{
"name":"p2",
"evaluationStrategy":"BY_VALUE",
"code":"p2",
"typeFullName":"ANY",
"order":2,
"_label":"METHOD_PARAMETER_IN",
"id":1000162
},
{
"evaluationStrategy":"BY_VALUE",
"code":"RET",
"typeFullName":"ANY",
"order":-1,
"_label":"METHOD_RETURN",
"id":1000163
},
{
"code":"",
"typeFullName":"ANY",
"order":1,
"_label":"BLOCK",
"argumentIndex":1,
"id":1000164
},
{
"name":".assignment",
"astParentFullName":"",
"fullName":".assignment",
"signature":"TODO",
"astParentType":"NAMESPACE_BLOCK",
"_label":"METHOD",
"code":"",
"isExternal":true,
"id":1000165,
"order":0,
"filename":""
},
{
"name":"p1",
"evaluationStrategy":"BY_VALUE",
"code":"p1",
"typeFullName":"ANY",
"order":1,
"_label":"METHOD_PARAMETER_IN",
"id":1000166
},
{
"name":"p2",
"evaluationStrategy":"BY_VALUE",
"code":"p2",
"typeFullName":"ANY",
"order":2,
"_label":"METHOD_PARAMETER_IN",
"id":1000167
},
{
"evaluationStrategy":"BY_VALUE",
"code":"RET",
"typeFullName":"ANY",
"order":-1,
"_label":"METHOD_RETURN",
"id":1000168
},
{
"code":"",
"typeFullName":"ANY",
"order":1,
"_label":"BLOCK",
"argumentIndex":1,
"id":1000169
},
{
"name":".sizeOf",
"astParentFullName":"",
"fullName":".sizeOf",
"signature":"TODO",
"astParentType":"NAMESPACE_BLOCK",
"_label":"METHOD",
"code":"",
"isExternal":true,
"id":1000170,
"order":0,
"filename":""
},
{
"name":"p1",
"evaluationStrategy":"BY_VALUE",
"code":"p1",
"typeFullName":"ANY",
"order":1,
"_label":"METHOD_PARAMETER_IN",
"id":1000171
},
{
"evaluationStrategy":"BY_VALUE",
"code":"RET",
"typeFullName":"ANY",
"order":-1,
"_label":"METHOD_RETURN",
"id":1000172
},
{
"code":"",
"typeFullName":"ANY",
"order":1,
"_label":"BLOCK",
"argumentIndex":1,
"id":1000173
},
{
"name":"argc",
"evaluationStrategy":"BY_VALUE",
"code":"int argc",
"typeFullName":"int",
"columnNumber":9,
"order":1,
"_label":"METHOD_PARAMETER_OUT",
"lineNumber":1,
"id":1000174
},
{
"name":"argv",
"evaluationStrategy":"BY_VALUE",
"code":"char **argv",
"typeFullName":"char * *",
"columnNumber":19,
"order":2,
"_label":"METHOD_PARAMETER_OUT",
"lineNumber":1,
"id":1000175
},
{
"name":"p1",
"evaluationStrategy":"BY_VALUE",
"code":"p1",
"typeFullName":"ANY",
"order":1,
"_label":"METHOD_PARAMETER_OUT",
"id":1000176
},
{
"name":"p2",
"evaluationStrategy":"BY_VALUE",
"code":"p2",
"typeFullName":"ANY",
"order":2,
"_label":"METHOD_PARAMETER_OUT",
"id":1000177
},
{
"name":"p1",
"evaluationStrategy":"BY_VALUE",
"code":"p1",
"typeFullName":"ANY",
"order":1,
"_label":"METHOD_PARAMETER_OUT",
"id":1000178
},
{
"name":"p2",
"evaluationStrategy":"BY_VALUE",
"code":"p2",
"typeFullName":"ANY",
"order":2,
"_label":"METHOD_PARAMETER_OUT",
"id":1000179
},
{
"name":"p1",
"evaluationStrategy":"BY_VALUE",
"code":"p1",
"typeFullName":"ANY",
"order":1,
"_label":"METHOD_PARAMETER_OUT",
"id":1000180
},
{
"name":"p2",
"evaluationStrategy":"BY_VALUE",
"code":"p2",
"typeFullName":"ANY",
"order":2,
"_label":"METHOD_PARAMETER_OUT",
"id":1000181
},
{
"name":"p1",
"evaluationStrategy":"BY_VALUE",
"code":"p1",
"typeFullName":"ANY",
"order":1,
"_label":"METHOD_PARAMETER_OUT",
"id":1000182
},
{
"name":"p2",
"evaluationStrategy":"BY_VALUE",
"code":"p2",
"typeFullName":"ANY",
"order":2,
"_label":"METHOD_PARAMETER_OUT",
"id":1000183
},
{
"name":"p1",
"evaluationStrategy":"BY_VALUE",
"code":"p1",
"typeFullName":"ANY",
"order":1,
"_label":"METHOD_PARAMETER_OUT",
"id":1000184
},
{
"name":"p2",
"evaluationStrategy":"BY_VALUE",
"code":"p2",
"typeFullName":"ANY",
"order":2,
"_label":"METHOD_PARAMETER_OUT",
"id":1000185
},
{
"name":"p1",
"evaluationStrategy":"BY_VALUE",
"code":"p1",
"typeFullName":"ANY",
"order":1,
"_label":"METHOD_PARAMETER_OUT",
"id":1000186
},
{
"name":"",
"order":0,
"_label":"FILE",
"id":1000187
},
{
"name":"/home/yu/bin/joern/Example.c",
"order":0,
"_label":"FILE",
"id":1000188
},
{
"id":1000189,
"name":"",
"order":-1,
"_label":"NAMESPACE"
}
]
像这种记录:
{
"name":"argc",
"evaluationStrategy":"BY_VALUE",
"code":"int argc",
"typeFullName":"int",
"columnNumber":9,
"order":1,
"_label":"METHOD_PARAMETER_IN",
"lineNumber":1,
"id":1000101
},
就包含了节点1000101的Line Number,通过这种命令行的方式,我们就可以实现批量处理了。不得不说,Joern这个项目的开发人员脑子太不清楚了,这么简单的需求,难道不是应该一个命令搞定的事情么?Anyway,还是要真诚感谢为大家开源做贡献的人。