Identify annotated variable in an LLVM pass

Viewed 1251

How can I identify an annotated variable in an LLVM pass?

#include <stdio.h>

int main (){
int x __attribute__((annotate("my_var")))= 0;
int a,b;
x = x + 1;
a = 5;
b = 6;
x = x + a;

return x;
}

For example, I want to identify the instructions which have the annotated variable (x in this case) and print them out (x = x+1; and x = x+a) How can I achieve this?

This is the .ll file generated using LLVM

    ; ModuleID = 'test.c'
source_filename = "test.c"
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64"

@.str = private unnamed_addr constant [7 x i8] c"my_var\00", section "llvm.metadata"
@.str.1 = private unnamed_addr constant [7 x i8] c"test.c\00", section "llvm.metadata"

; Function Attrs: noinline nounwind optnone
define i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  %3 = alloca i32, align 4
  %4 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  %5 = bitcast i32* %2 to i8*
  call void @llvm.var.annotation(i8* %5, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.s$
  store i32 0, i32* %2, align 4
  %6 = load i32, i32* %2, align 4
  %7 = add nsw i32 %6, 1
  store i32 %7, i32* %2, align 4
  store i32 5, i32* %3, align 4
  store i32 6, i32* %4, align 4
  %8 = load i32, i32* %2, align 4
  %9 = load i32, i32* %3, align 4
  %10 = add nsw i32 %8, %9
  store i32 %10, i32* %2, align 4
  %11 = load i32, i32* %2, align 4
  ret i32 %11
}

; Function Attrs: nounwind
declare void @llvm.var.annotation(i8*, i8*, i8*, i32) #1

attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" $
attributes #1 = { nounwind }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
!0 = !{i32 1, !"wchar_size", i32 4}
2 Answers

I recently encountered similiary problem, as I searched Google still not found a solution. But in the end , I found "ollvm" project's Utils.cpp ,it solved my problem.

In your case,

    %5 = bitcast i32* %2 to i8*
  call void @llvm.var.annotation(i8* %5, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.s$

as we can see there is a call to @llvm.var.annotation , in our pass , we can loop through instructions over a function , and search for "call" instruction. Then get the called function's name:

Function *fn = callInst->getCalledFunction();

            StringRef fn_name = fn->getName();

and compare the called function's name with "llvm.var.annotation" . If they match ,then we found the location of "int x " in your case . The function "llvm.var.annotation" is documented in llvm's doc : http://llvm.org/docs/LangRef.html#llvm-var-annotation-intrinsic

If you have learn the function "llvm.var.annotation"'s prototype, then you know that it's second argument is a pointer ,the pointer points to "my_var\00" in your case . If you thought you can simply convert it to a GlobalVariable ,then you will failed to get what you wanted . The actual second argument passed to "llvm.var.annotation" is

i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.s$
in your case. It's a expression but a GlobalVariable !!! By knowing this , we can finally get the annotation of our target variable by :

ConstantExpr *ce =
                  cast<ConstantExpr>(callInst->getOperand(1));
              if (ce) {
                if (ce->getOpcode() == Instruction::GetElementPtr) {
                  if (GlobalVariable *annoteStr =
                          dyn_cast<GlobalVariable>(ce->getOperand(0))) {
                    if (ConstantDataSequential *data =
                            dyn_cast<ConstantDataSequential>(
                                annoteStr->getInitializer())) {
                      if (data->isString()) {
                        errs() << "Found data " << data->getAsString();
                      }
                    }
                  }
                }

Hope you already solved the problem . Have a nice day .

Related