How does LLDB find inlined functions? - c++

When setting a breakpoint by specifying a Symbol Name, lldb not only resolves that symbol, but also finds where the function has been used inlined. How is that possible?
1: name = 'my_func', locations = 4, resolved = 1, hit count = 1
1.1: where = kernel.development`my_func + 6 at task.c:17, address = 0xxxx, resolved, hit count = 0
1.2: where = kernel.development`func_foo + 119 [inlined] my_func at task.c:22, address = 0xxxx, unresolved, hit count = 0 Options: disabled
1.3: where = kernel.development`func_bar + 95 [inlined] my_func at task.c:65, address = 0xxxx, unresolved, hit count = 1 Options: disabled
Looking at LLDB's source, I could only find where it checked if a certain block is inlined: //source/API/SBBlock.cpp
bool SBBlock::IsInlined() const {
LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBBlock, IsInlined);
if (m_opaque_ptr)
return m_opaque_ptr->GetInlinedFunctionInfo() != nullptr;
return false;
}

An LLDB testcase in split-dwarf-inlining.cpp confirms that DWARF debug information is used to find inline functions.
// RUN: %clangxx -target x86_64-pc-linux -gsplit-dwarf -fsplit-dwarf-inlining \
// RUN: -c %s -o %t
// RUN: %lldb %t -o "breakpoint set -n foo" -b | FileCheck %s
// CHECK: Breakpoint 1: 2 locations
__attribute__((always_inline)) int foo(int x) { return x; }
int bar(int x) { return foo(x); }

If you run dwarfinfo on an executable it'll show "nested" inline methods, so that's how it finds it.
Where it actually finds it:
GetBlock:
Gets the deepest block that contains the frame PC.
https://github.com/llvm-mirror/lldb/blob/d01083a850f577b85501a0902b52fd0930de72c7/include/lldb/API/SBFrame.h#L60
deepest block I believe refers to the inline methods being "nested."
Then it can call getInlinedParent or getParent on that "lowest block" to generate the output. Something like that...

Related

Cannot resolve symbols by ReexportsGenerator in LLVM ORC JIT

I'm not good in LLVM so please forgive me wrong termins. There is an issue with JIT session error: Symbols not found when trying "lookup" functions from one module which depends on functions from another module. So there are two LLJIT instances:
llvm::orc::JITDylib &JD = JIT2->getMainJITDylib();
llvm::orc::JITDylib &SourceJD = JIT1->getMainJITDylib();
I wanted utilize ReexportsGenerator as it sounds applicable for my problem (see addGenerator), however the following generator approach doesn't work
auto gen = std::make_unique<ReexportsGenerator>(JIT1->getMainJITDylib(),
llvm::orc::JITDylibLookupFlags::MatchAllSymbols);
JIT2->getMainJITDylib().addGenerator(std::move(gen));
So when I tried go deeper to the generator's implementation, I've found that lookupFlags cannot match desired symbols while lookup return an address with no exceptions:
llvm::StringRef symName("my_symbol_name");
llvm::orc::SymbolStringPool pool;
llvm::orc::SymbolStringPtr symNamePtr = pool.intern(symName);
// Try just lookup the symbol
auto addr = JIT1->lookup(symName);
if (auto E = addr.takeError()) {
throw E;
}
uint64_t fun_addr = addr->getValue(); // contains correct value so I'm sure that JIT1 has my symbol
But number of matches from lookupFlags is 0:
// Try symbols resolving
llvm::orc::SymbolLookupSet LookupSet;
LookupSet.add(symNamePtr, llvm::orc::SymbolLookupFlags::WeaklyReferencedSymbol);
auto Flags = JD.getExecutionSession().lookupFlags(
llvm::orc::LookupKind::DLSym,
{{&SourceJD, llvm::orc::JITDylibLookupFlags::MatchAllSymbols}},
LookupSet);
if (auto E = Flags.takeError()) {
throw E;
}
std::cout << "Flags.size() " << (*Flags).size() << std::endl;
My question is, what I have not considered while applied such symbol resolving approach? I'm confused why lookup is able to find the symbol while lookupFlags not.

Function optimization pass

I am trying to use llvm::PassBuilder and FunctionPassManager to optimize a function in a module, what I have done is:
mod = ...load module from LLVM IR bitcode file...
auto lift_func = mod->getFunction("go_back");
if (not lift_func) {
llvm::errs() << "Error: cannot get function\n";
return 0;
}
auto pass_builder = llvm::PassBuilder{};
auto fa_manager = llvm::FunctionAnalysisManager{};
pass_builder.registerFunctionAnalyses(fa_manager);
auto fp_manager = pass_builder.buildFunctionSimplificationPipeline(llvm::PassBuilder::OptimizationLevel::O2);
fp_manager.run(*lift_func, fa_manager);
but the program crashes always at fp_manager.run. I tried several ways with pass_builder, fa_manager, fp_manager but nothing works.
Strange enough, the LLVM's opt tool (which uses legacy optimization interface) works without any problem, i.e. if I run
opt -O2 go_back.bc -o go_back_o2.bc
then I get a new module where the (single) function go_back is optimized.
Many thanks for any response.
NB. The (disassembled) LLVM bitcode file is given here if anyone wants to take a look.
Update: I've somehow managed to pass the fp_manager.run with:
auto loop_manager = llvm::LoopAnalysisManager{};
auto cgscc_manager = llvm::CGSCCAnalysisManager{};
auto mod_manager = llvm::ModuleAnalysisManager{};
pass_builder.registerModuleAnalyses(mod_manager);
pass_builder.registerCGSCCAnalyses(cgscc_manager);
pass_builder.registerFunctionAnalyses(fa_manager);
pass_builder.registerLoopAnalyses(loop_manager);
pass_builder.crossRegisterProxies(loop_manager, fa_manager, cgscc_manager, mod_manager);
auto fp_manager = pass_builder.buildFunctionSimplificationPipeline(llvm::PassBuilder::OptimizationLevel::O2, llvm::PassBuilder::ThinLTOPhase::None, true);
fp_manager.run(*lift_func, fa_manager);
...print mod...
But the program crashes when the fa_manager object is destroyed, still do not understand why!!!
Well, after debugging and reading LLVM source code, I've managed to make it works, as following
mod = ...load module from LLVM IR bitcode file...
auto lift_func = mod->getFunction("go_back");
if (not lift_func) {
llvm::errs() << "Error: cannot get function\n";
return 0;
}
auto pass_builder = llvm::PassBuilder{};
auto loop_manager = llvm::LoopAnalysisManager{};
auto cgscc_manager = llvm::CGSCCAnalysisManager{};
auto mod_manager = llvm::ModuleAnalysisManager{};
auto fa_manager = llvm::FunctionAnalysisManager{}; // magic: it's must be here
pass_builder.registerModuleAnalyses(mod_manager);
pass_builder.registerCGSCCAnalyses(cgscc_manager);
pass_builder.registerFunctionAnalyses(fa_manager);
pass_builder.registerLoopAnalyses(loop_manager);
pass_builder.crossRegisterProxies(loop_manager, fa_manager, cgscc_manager, mod_manager);
auto fp_manager = pass_builder.buildFunctionSimplificationPipeline(llvm::PassBuilder::OptimizationLevel::O2, llvm::PassBuilder::ThinLTOPhase::None, true);
fp_manager.run(*lift_func, fa_manager);
...anything...
The fa_manager should be initialized as late as possible, I still don't know why!!!

Dump Block Liveness of source code using Clang

I need to dump the block liveness of source code using clang's API. I have tried printing the block liveness but got no success. Below is the code that I have tried
bool MyASTVisitor::VisitFunctionDecl(FunctionDecl *f) {
std::cout<<"Dump Liveness\n";
clang::AnalysisDeclContextManager adcm;
clang::AnalysisDeclContext *adc = adcm.getContext(llvm::cast<clang::Decl>(f));
//clang::LiveVariables *lv = clang::LiveVariables::create(*adc);
//clang::LiveVariables *lv = clang::LiveVariables::computeLiveness(*adc,false);
clang::LiveVariables *lv = adc->getAnalysis<LiveVariables>();
clang::LiveVariables::Observer *obs = new clang::LiveVariables::Observer();
lv->runOnAllBlocks(*obs);
lv->dumpBlockLiveness((f->getASTContext()).getSourceManager());
return true;
}
I have override Visitor Functions and have tried printing the liveness of a function. I have tried using create, computeLiveness and getAnalysis methods to get the LiveVariables object, but all the approaches failed. However no Liveness Information is displayed except the block numbers.
When I use command line arguments of clang to print the liveness it displays the output correctly.
I am using the following source code as test case taken from Live Variable Analysis Wikipedia
.
int main(int argc, char *argv[])
{
int a,b,c,d,x;
a = 3;
b = 5;
d = 4;
x = 100;
if(a>b){
c = a+b;
d = 2;
}
c = 4;
return b * d + c;
}
Could someone please point out where could I be wrong?
Thanks in advance.
I had the same issue, after some debugging of clang -cc1 -analyze -analyzer-checker=debug.DumpLiveVars I finally found the answer !
The issue is that the LiveVariables analysis does not explores sub-expressions (such as DeclRefExpr) by itself. It only relies on the CFG enumeration. By default the CFG only enumerates top-level statements.
You must call adc->getCFGBuildOptions().setAllAlwaysAdd() before getting any analysis from your AnalysisDeclContext. This will create elements for all sub-expressions in the CFGBlocks of the control-flow-graph.

llvm callgraphscc pass causes core dump

I wrote an llvm callgraphscc pass, it's very simple as following:
bool MyCallGraphSCCPass::runOnSCC(CallGraphSCC& SCC) {
for (CallGraphSCC::iterator it = SCC.begin(); it != SCC.end(); it++) {
CallGraphNode* node = *it;
Function* func = node->getFunction();
}
return false;
}
This just works fine. However, if I want to print the name of each function as following:
bool MyCallGraphSCCPass::runOnSCC(CallGraphSCC& SCC) {
for (CallGraphSCC::iterator it = SCC.begin(); it != SCC.end(); it++) {
CallGraphNode* node = *it;
Function* func = node->getFunction();
func->getName();
}
return false;
}
Then it can compile (obviously), but when I use opt to run this, there appears an error as following:
0 opt 0x0000000001603412 llvm::sys::PrintStackTrace(_IO_FILE*) + 34
1 opt 0x0000000001602cb4
2 libpthread.so.0 0x00007fd3155f8cb0
3 opt 0x00000000014a86e0 llvm::AttributeSet::getAttributes(unsigned int) const + 0
4 opt 0x00000000014a8748 llvm::AttributeSet::hasAttribute(unsigned int, llvm::Attribute::AttrKind) const + 8
5 call_graph_scc_pass.so 0x00007fd3146062ad test::MyCallGraphSCCPass::runOnSCC(llvm::CallGraphSCC&) + 61
6 opt 0x00000000012aa9aa
7 opt 0x0000000001591188 llvm::legacy::PassManagerImpl::run(llvm::Module&) + 904
8 opt 0x000000000059387b main + 2811
9 libc.so.6 0x00007fd31482976d __libc_start_main + 237
10 opt 0x00000000005b700d
Stack dump:
0. Program arguments: opt -load call_graph_scc_pass.so -scc
1. Running pass 'CallGraph Pass Manager' on module '<stdin>'.
Segmentation fault (core dumped)
Can some one help me with this?
You should check whether the function in the CallGraph is isDeclaration() or not.
This is because node->getFunction() may return a null-pointer and you're not checking for this before dereferencing it.
A CallGraphNode is added to the call graph for all functions in the module without internal linkage. This is because there is a possibility that it could be called from another module. Of course, this is not reachable from the current module, so the caller function is null.
A CallGraphNode is also added if a function address is used for something other than a direct call (such as being stored into memory). It may be called later in a way that the caller can't be tracked statically, so the function field is null here too.

Couldn't determine value's most derived type for dynamic_cast

Recently I am working on the python extension of gdb7, I just want to use it to write a small tool to display the contents of C++ containers (such as list) friendly while debugging.But I got trouble when dealing with list. This is my C++ code for test use:
int main() {
list<int> int_lst;
for (int i = 0; i < 10; ++i)
int_lst.push_back(i);
for(list<int>::const_iterator citer = int_lst.begin();
citer != int_lst.end(); ++citer)
cout << *citer << " ";
cout << endl;
return 0;
}
And I write a small python code following the 'debugging with gdb' tutorial just try to display contents of int_lst
import gdb
class Hello(gdb.Command):
def __init__(self):
super(Hello, self).__init__("plist", gdb.COMMAND_OBSCURE)
def invoke(self, arg, from_tty):
cpp_lst = gdb.parse_and_eval("int_lst")
header = cpp_lst['_M_impl']['_M_node']
next = header['_M_next']
# next is _List_node_base, I have to cast it to its derived type for data
next.dynamic_cast(gdb.lookup_type("std::_List_node<``int>").pointer())
Hello()
In C++ STL, std::_List_node_base is the base class of nodes in list, however only the derived template class std::_List_node has the data member "_M_data" which contains the value, so I have to dynamic_cast it, but gdb complains:
Error occurred in Python command: Couldn't determine value's most derived type for dynamic_cast
I've spent a few hours on it, could anyone experienced offer me some hints about this problem, or any suggestions for me to accomplish this little tool? I really appreciate your help, thanks!
It is difficult to say what went wrong without more information.
GDB is trying to use the RTTI information to find the full object for that field. This is failing for some eason. You can try to reproduce the problem from the CLI by using "set print object on" and then printing the field in question.
Alternatively, is there a particular reason you want to use dynamic_cast? Just use the plain "cast" method instead. I think that will bypass these checks.
Note that for this specific case, you probably should just pick up the existing libstdc++ pretty-printers. These integrate with the existing "print" command in gdb and already handle every complicated data structure in libstdc++. Many distros ship all of this code in a way that automatically enables it when your program uses libstdc++.
I see the same error from dynamic_cast() as well. Using cast() instead of dynamic_cast() there works:
list-pretty-print.cc
#include <iostream>
#include <list>
/* https://github.com/scottt/debugbreak */
#include "debugbreak/debugbreak.h"
using namespace std;
int main()
{
list<int> int_lst;
debug_break();
for (int i = 0; i < 10; ++i)
int_lst.push_back(i);
debug_break();
for(list<int>::const_iterator citer = int_lst.begin();
citer != int_lst.end(); ++citer)
cout << *citer << " ";
cout << endl;
return 0;
}
list-pretty-print.py
import gdb
class PList(gdb.Command):
def __init__(self):
super(PList, self).__init__('plist', gdb.COMMAND_OBSCURE)
def invoke(self, arg, from_tty):
int_list_pointer_type = gdb.lookup_type('std::_List_node<int>').pointer()
lst = gdb.parse_and_eval('int_lst')
node = lst['_M_impl']['_M_node']
nxt = node['_M_next']
if node.address == nxt:
gdb.write('{}\n')
return
else:
gdb.write('{')
while True:
e = nxt.cast(int_list_pointer_type).dereference()
gdb.write('%d, ' % (e['_M_data'],))
nxt = e['_M_next']
if node.address == nxt:
gdb.write('}\n')
return
PList()
test-list-pretty-print.gdb
set confirm off
set pagination off
set python print-stack full
file list-pretty-print
source list-pretty-print.py
run
up 2
plist
continue
up 2
plist
quit
Sample Session
$ gdb -q -x test-list-pretty-print.gdb
Program received signal SIGTRAP, Trace/breakpoint trap.
trap_instruction () at list-pretty-print.cc:15
15 for (int i = 0; i < 10; ++i)
#2 main () at list-pretty-print.cc:13
13 debug_break();
{}
Program received signal SIGTRAP, Trace/breakpoint trap.
trap_instruction () at list-pretty-print.cc:20
20 for(list<int>::const_iterator citer = int_lst.begin();
#2 main () at list-pretty-print.cc:18
18 debug_break();
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, }
Looking at the chain of expressions, I'm not sure dynamic_cast() is supposed to work there:
(gdb) whatis int_lst
type = std::list<int, std::allocator<int> >
(gdb) whatis int_lst._M_impl
type = std::_List_base<int, std::allocator<int> >::_List_impl
(gdb) whatis int_lst._M_impl._M_node._M_next
type = std::__detail::_List_node_base *
(gdb) python print gdb.parse_and_eval('int_lst._M_impl._M_node._M_next').dynamic_type
std::__detail::_List_node_base *
(gdb) python print gdb.parse_and_eval('int_lst._M_impl._M_node._M_next').dynamic_cast(gdb.lookup_type('std::_List_node<int>').pointer())
Traceback (most recent call last):
File "<string>", line 1, in <module>
gdb.error: Couldn't determine value's most derived type for dynamic_cast
Error while executing Python code.