llvm-tutor icon indicating copy to clipboard operation
llvm-tutor copied to clipboard

Is it possible to obtain and print the specified local variable value by llvm pass?

Open songxpu opened this issue 3 years ago • 3 comments

Hello, I just started to learn llvm pass. You must be very professional in llvm pass, so I want to ask a practical question, as the title says. For example, this is a very simple program.

#include <stdlib.h>

int main(){
	int a=0;
	for(int i=0;i<5;i++){
		a++;
	}
	return 0;
}

Can I dynamically obtain the value of local variable a in llvm pass? My purpose is to observe its value change When it changes. So I have to obtain the value of the local variable a firstly.

If it's a global variable, it should be very simple to obtain its value, but I don't have any ideas about local variables.

I have checked the official documents and don't know whether this can be realized. If so, can you provide some ideas?

songxpu avatar Aug 12 '21 15:08 songxpu

Hi @songxpu ,

Thank you for stopping by :) Unfortunately, I'm not aware of an easy ways of achieving this. You will probably have to use the debug info to track any source-level variables. That should be doable, but I've never tried it myself. Let me know how you get on - I'd be curious to see the end result myself!

Best, -Andrzej

banach-space avatar Aug 14 '21 18:08 banach-space

Hi @banach-space ,thanks for your reply :)

After two days of study, my thoughts are similar to yours, that is, debug info may be needed to achieve this goal. In fact, when this question was raised 4 days ago, I wanted to know how to get the return value of an instruction. Now my problem is solved, that is, the return value of the instruction is the instruction itself.

So I can insert a custom function and pass the instruction of the target variable as a parameter to this function to get its value. Of course, this is only a small step, there are more things to be solved in the next step.

songxpu avatar Aug 16 '21 12:08 songxpu

Hi @songxpu, what do you mean by 'obtain the value of local variable a in llvm pass'? The LLVM pass sees the code before it is executed. So I presume you mean you want to observe the value at runtime, therefore you want your pass to insert code which allows the value to be observed at runtime? For example, would you consider this case satisfied if you had a pass which inserted the equivalent of a 'printf()' whenever the variable a is modified during execution, or do you mean something else?

pwaller avatar Nov 02 '21 21:11 pwaller

how to use debug info to find local variables? Which API should I use?

Nicholas-wei avatar Nov 12 '22 07:11 Nicholas-wei

Hey @Nicholas-wei , thanks for visiting 👋!

In general, I feel that this question is much more suitable for https://discourse.llvm.org/. This way it would get more visibility - that’s where most LLVM experts are :) Also, that’s where others will seek answers for similar questions.

Closing this as is - please post on Discourse instead :)

banach-space avatar Nov 12 '22 09:11 banach-space

I came across this question while searching for answers for the same question, here are my quick experiments. My goal is also to be able to generate code to print the value of certain variables during run-time.

With the following code in an LLVM pass:

bool runOnFunction(Function &F) override {
      for (Function::iterator itr = F.begin(); itr != F.end(); itr++) {
...
        BasicBlock& bb = *itr;
...
        for (BasicBlock::iterator itr2 = bb.begin(); itr2 != bb.end(); itr2++) {
          Instruction& instr = *itr2;
...
          if (isa<CallInst>(instr)) {
            CallInst& ci = cast<CallInst>(instr);
            for (User::op_iterator itr3 = ci.arg_begin(); itr3 != ci.arg_end(); itr3++) {
              Value* value = itr3->get();
...
              } else if (isa<MetadataAsValue>(*value)) {
                Metadata* md = cast<MetadataAsValue>(*value).getMetadata();
                unsigned char mdid = md->getMetadataID();
                fprintf(stderr, " MetadataAsValue ID=%u(%s", mdid, GetMetadataKind(md));
                if (isa<DILocalVariable>(*md)) {
                  DILocalVariable& dil = cast<DILocalVariable>(*md);
                  fprintf(stderr, " \"%s\"", dil.getName().data());
                }
...

If you have the following program:

int main() { int a = 1; }

The program when compiled with -g, will result in a call instruction to "llvm.dbg.declare".

define dso_local i32 @main() #4 !dbg !1563 {
  %1 = alloca i32, align 4
  call void @llvm.dbg.declare(metadata i32* %1, metadata !1564, metadata !DIExpression()), !dbg !1565
  store i32 1, i32* %1, align 4, !dbg !1565
...

Then, when the pass is run, it will print the name of the local variable, "a".

I think one can keep track of the CXX scope to learn which variables (global, class, extern, etc) are visible and do thing upon them.

quadpixels avatar Dec 25 '22 10:12 quadpixels

Thank you! That perfectly solves my question

Nicholas-wei avatar Dec 25 '22 10:12 Nicholas-wei

Thanks for sharing @quadpixels !

Clearly there’s more people interested in this - have you considered creating an llvm-tutor example out of this? Happy to review one ;-)

banach-space avatar Dec 25 '22 21:12 banach-space