AST info parser for edk2 - shijunjing/edk2 GitHub Wiki

Edk2 AST parser based on Clang LibTooling and LibASTMatchers https://github.com/shijunjing/edk2/wiki/Try-tutorial-for-building-tools-using-LibTooling-and-LibASTMatchers

Linux build:

jshi19@ub2-uefi-b01:~/llvm/llvm-project/LibASTMatchersTutorial$ git status
On branch edk2-metrics

jshi19@ub2-uefi-b01:~/llvm/llvm-project/LibASTMatchersTutorial$ cmake -G Ninja ../llvm -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DCMAKE_BUILD_TYPE="MinSizeRel" -DLLVM_TARGETS_TO_BUILD="X86" -DCMAKE_INSTALL_PREFIX=../minsizerelinstall/ -DLLVM_ENABLE_Z3_SOLVER=OFF -DLLVM_CCACHE_BUILD=ON
jshi19@ub2-uefi-b01:~/llvm/llvm-project/LibASTMatchersTutorial$ ninja edk2-ast-parser
jshi19@ub2-uefi-b01:~/llvm/llvm-project/LibASTMatchersTutorial$ bin/edk2-ast-parser ~/llvm/wrongcode/loop-convert/simple-loops.cc
Error while trying to load a compilation database:
Could not auto-detect compilation database for file "/home/jshi19/llvm/wrongcode/loop-convert/simple-loops.cc"
No compilation database found in /home/jshi19/llvm/wrongcode/loop-convert or any parent directory
fixed-compilation-database: Error while opening fixed database: No such file or directory
json-compilation-database: Error while opening JSON database: No such file or directory
Running without flags.
FunctionPrinter is called:0times
/usr/include/x86_64-linux-gnu/bits/libio.h:_IO_cookie_init:380:13
FunctionPrinter is called:1times
... ...
/usr/include/stdio.h:ftrylockfile:844:12
FunctionPrinter is called:117times
/usr/include/stdio.h:funlockfile:847:13
FunctionPrinter is called:118times
/home/jshi19/llvm/wrongcode/loop-convert/simple-loops.cc:DMA_Read:6:6
FunctionDecl 0x55fd1926a680 </home/jshi19/llvm/wrongcode/loop-convert/simple-loops.cc:6:1, line:18:1> line:6:6 used DMA_Read 'void (void *, int)'
|-ParmVarDecl 0x55fd1926a520 <col:15, col:22> col:22 buffer 'void *'
|-ParmVarDecl 0x55fd1926a5a0 <col:30, col:34> col:34 used size 'int'
`-CompoundStmt 0x55fd1926c028 <col:39, line:18:1>
  |-DeclStmt 0x55fd1926a870 <line:8:3, line:4:35>
  | `-VarDecl 0x55fd1926a748 <line:8:3, line:4:21> line:8:7 used datalen 'int' cinit
  |   `-ImplicitCastExpr 0x55fd1926a858 <col:17, line:4:21> 'int' <LValueToRValue>
  |     `-UnaryOperator 0x55fd1926a840 <line:8:17, line:4:21> 'volatile int' lvalue prefix '*' cannot overflow
  |       `-CStyleCastExpr 0x55fd1926a818 <line:8:18, line:4:21> 'volatile int *' <IntegralToPointer>
  |         `-IntegerLiteral 0x55fd1926a7b0 <col:21> 'long' 140729166944016
  |-NullStmt 0x55fd1926a888 <line:8:44>
  |-CallExpr 0x55fd1926aa48 <line:9:3, col:34> 'int'
  | |-ImplicitCastExpr 0x55fd1926aa30 <col:3> 'int (*)(const char *__restrict, ...)' <FunctionToPointerDecay>
  | | `-DeclRefExpr 0x55fd1926a9a8 <col:3> 'int (const char *__restrict, ...)' lvalue Function 0x55fd192584c0 'printf' 'int (const char *__restrict, ...)'
  | |-ImplicitCastExpr 0x55fd1926aa78 <col:10> 'const char *' <ArrayToPointerDecay>
  | | `-StringLiteral 0x55fd1926a960 <col:10> 'const char [13]' lvalue "datalen=%d \n"
  | `-ImplicitCastExpr 0x55fd1926aa90 <col:27> 'int' <LValueToRValue>
  |   `-DeclRefExpr 0x55fd1926a988 <col:27> 'int' lvalue Var 0x55fd1926a748 'datalen' 'int'
  `-IfStmt 0x55fd1926c000 <line:10:3, line:17:3> has_else
    |-BinaryOperator 0x55fd1926ab18 <line:10:6, col:14> 'bool' '>='
    | |-ImplicitCastExpr 0x55fd1926aae8 <col:6> 'int' <LValueToRValue>
    | | `-DeclRefExpr 0x55fd1926aaa8 <col:6> 'int' lvalue ParmVar 0x55fd1926a5a0 'size' 'int'
    | `-ImplicitCastExpr 0x55fd1926ab00 <col:14> 'int' <LValueToRValue>
    |   `-DeclRefExpr 0x55fd1926aac8 <col:14> 'int' lvalue Var 0x55fd1926a748 'datalen' 'int'
    |-CompoundStmt 0x55fd1926ae20 <col:22, line:14:3>
    | |-CallExpr 0x55fd1926ac68 <line:11:5, col:33> 'int'
    | | |-ImplicitCastExpr 0x55fd1926ac50 <col:5> 'int (*)(const char *__restrict, ...)' <FunctionToPointerDecay>
    | | | `-DeclRefExpr 0x55fd1926ac30 <col:5> 'int (const char *__restrict, ...)' lvalue Function 0x55fd192584c0 'printf' 'int (const char *__restrict, ...)'
    | | `-ImplicitCastExpr 0x55fd1926ac90 <col:12> 'const char *' <ArrayToPointerDecay>
    | |   `-StringLiteral 0x55fd1926ac00 <col:12> 'const char [19]' lvalue "Start reading DMA\n"
    | `-CallExpr 0x55fd1926ade0 <line:13:5, col:41> 'int'
    |   |-ImplicitCastExpr 0x55fd1926adc8 <col:5> 'int (*)(const char *__restrict, ...)' <FunctionToPointerDecay>
    |   | `-DeclRefExpr 0x55fd1926ada8 <col:5> 'int (const char *__restrict, ...)' lvalue Function 0x55fd192584c0 'printf' 'int (const char *__restrict, ...)'
    |   `-ImplicitCastExpr 0x55fd1926ae08 <col:12> 'const char *' <ArrayToPointerDecay>
    |     `-StringLiteral 0x55fd1926ad70 <col:12> 'const char [27]' lvalue "DMA transfer is triggered\n"
    `-CompoundStmt 0x55fd1926bfe8 <line:14:8, line:17:3>
      `-CallExpr 0x55fd1926bfa8 <line:15:5, col:36> 'int'
        |-ImplicitCastExpr 0x55fd1926bf90 <col:5> 'int (*)(const char *__restrict, ...)' <FunctionToPointerDecay>
        | `-DeclRefExpr 0x55fd1926bf70 <col:5> 'int (const char *__restrict, ...)' lvalue Function 0x55fd192584c0 'printf' 'int (const char *__restrict, ...)'
        `-ImplicitCastExpr 0x55fd1926bfd0 <col:12> 'const char *' <ArrayToPointerDecay>
          `-StringLiteral 0x55fd1926bf40 <col:12> 'const char [22]' lvalue "Buffer is too small.\n"

clang-query

Useful link: Exploring Clang Tooling Part 2: Examining the Clang AST with clang-query

  • The sample c code
jshi19@ub2-uefi-b01:~/llvm/llvm-project/LibASTMatchersTutorial$ cat ~/llvm/wrongcode/loop-convert/simple-loops.cc       
#include <stdio.h>

#define Log(str) printf(#str)
#define IO_LEN_ADDR 0x7ffe10015710;

int DMA_Read(void * buffer, int size){
  //assert(addr_check(buffer, size)==TRUE);
  int datalen = *(volatile int*)IO_LEN_ADDR;
  printf("datalen=%d \n", datalen);
  if(size >= datalen){
    printf("Start reading DMA\n");
    //DMAStart(buffer, datalen);
    printf("DMA transfer is triggered\n");
  }else{
    printf("Buffer is too small.\n");
    //... //exception handling
  }

  return 1;
}

typedef
int
(*FUN_CALL)(
  void  *buffer,
  int   size
  );

int main()
{
  int buffer[0x100];
  FUN_CALL fun_ptr = DMA_Read;
  for (int i = 0; i < 5; i++){
    printf("buffer address=%p \n", buffer);
    DMA_Read(buffer, 0x100);
    fun_ptr (buffer, 0x500);
    printf("buffer address=%x \n", fun_ptr (buffer, 0x500));
  }

  return 0;
}
  • Match all the function callee which are referred in a function definition:
jshi19@ub2-uefi-b01:~/llvm/llvm-project/LibASTMatchersTutorial$ bin/clang-query ~/llvm/wrongcode/loop-convert/simple-loops.cc
clang-query> set bind-root false
clang-query> m callExpr(hasAncestor(functionDecl().bind("caller"))).bind("callee")
... ...

Match #7:

/home/jshi19/llvm/wrongcode/loop-convert/simple-loops.cc:36:5: note: "callee" binds here
    fun_ptr (buffer, 0x500);
    ^~~~~~~~~~~~~~~~~~~~~~~
/home/jshi19/llvm/wrongcode/loop-convert/simple-loops.cc:29:1: note: "caller" binds here
int main()
^~~~~~~~~~

Match #8:

/home/jshi19/llvm/wrongcode/loop-convert/simple-loops.cc:37:5: note: "callee" binds here
    printf("buffer address=%x \n", fun_ptr (buffer, 0x500));
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/jshi19/llvm/wrongcode/loop-convert/simple-loops.cc:29:1: note: "caller" binds here
int main()
^~~~~~~~~~

Match #9:

/home/jshi19/llvm/wrongcode/loop-convert/simple-loops.cc:37:36: note: "callee" binds here
    printf("buffer address=%x \n", fun_ptr (buffer, 0x500));
                                   ^~~~~~~~~~~~~~~~~~~~~~~
/home/jshi19/llvm/wrongcode/loop-convert/simple-loops.cc:29:1: note: "caller" binds here
int main()
^~~~~~~~~~
9 matches.
  • Match the function which has callee:
clang-query> m functionDecl(hasDescendant(compoundStmt(has(callExpr().bind("callee"))))).bind("caller")

Match #1:

/home/jshi19/llvm/wrongcode/loop-convert/simple-loops.cc:9:3: note: "callee" binds here
  printf("datalen=%d \n", datalen);
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/jshi19/llvm/wrongcode/loop-convert/simple-loops.cc:6:1: note: "caller" binds here
int DMA_Read(void * buffer, int size){
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Match #2:

/home/jshi19/llvm/wrongcode/loop-convert/simple-loops.cc:34:5: note: "callee" binds here
    printf("buffer address=%p \n", buffer);
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/jshi19/llvm/wrongcode/loop-convert/simple-loops.cc:29:1: note: "caller" binds here
int main()
^~~~~~~~~~
2 matches.

Windows Build:

C:\steven\LLVM\llvm-project-fork\_build_debug>cmake ..\llvm -G "Visual Studio 15 2017" -A x64 -DCMAKE_VERBOSE_MAKEFILE=ON  -DCMAKE_BUILD_TYPE="Debug" -DLLVM_ENABLE_ASSERTIONS=ON -Thost=x64 -DLLVM_ENABLE_PROJECTS=clang;clang-tools-extra  -DCMAKE_INSTALL_PREFIX=C:\steven\LLVM\llvm-project-fork\_install_debug -DLLVM_ENABLE_Z3_SOLVER=OFF -DLLVM_TARGETS_TO_BUILD="X86"

click C:\steven\LLVM\llvm-project-fork_build_debug\LLVM.sln and open the VS2017 to build the edk2-ast-parster target (Solution'LLVM'-->Clang executables-->edk2-ast-parster)

C:\steven\LLVM\llvm-project-fork\_build_debug>Debug\bin\edk2-ast-parser.exe C:\steven\LLVM\wrongcode\loop-convert\simple-loops.cc
⚠️ **GitHub.com Fallback** ⚠️