symbol lookup error: .so.2 undefined symbol - symbols

How to solve this undefined symbol.
odroid#odroid:~/flycapture.2.9.3.43_armhf/bin$ sudo ./FlyCap2
./FlyCap2: symbol lookup error: /usr/lib/libflycapturegui.so.2: undefined symbol: ZN5Gnome5Glade3Xml6createERKSsRKN4Glib7ustringES7
odroid#odroid:~/flycapture.2.9.3.43_armhf/bin$ sudo ldconfig -v | grep fly
/sbin/ldconfig.real: Path `/lib/arm-linux-gnueabihf' given more than once
/sbin/ldconfig.real: Path `/usr/lib/arm-linux-gnueabihf' given more than once
/sbin/ldconfig.real: /lib/arm-linux-gnueabihf/ld-2.23.so is the dynamic linker, ignoring
/sbin/ldconfig.real: /usr/lib/libflycapture.so.2 is not a symbolic link
/sbin/ldconfig.real: /usr/lib/libflycapturegui.so.2 is not a symbolic link
libflycapture.so.2 -> libflycapture.so.2.9.3.43
libflycapturegui.so.2 -> libflycapturegui.so.2.9.3.43
odroid#odroid:~/flycapture.2.9.3.43_armhf/bin$ ls -lah /usr/lib | grep fly
-rw-r--r-- 1 root root 473K Jul 13 13:26 libflycapturegui.so
-rw-r--r-- 1 root root 473K Jul 13 13:26 libflycapturegui.so.2
-rw-r--r-- 1 root root 473K Jul 13 13:26 libflycapturegui.so.2.9.3.43
-rw-r--r-- 1 root root 3.3M Jul 13 13:26 libflycapture.so
-rw-r--r-- 1 root root 3.3M Jul 13 13:26 libflycapture.so.2
-rw-r--r-- 1 root root 3.3M Jul 13 13:26 libflycapture.so.2.9.3.43

First, we can look at the information available, and use that to begin searching. As you're using Linux, it's most likely a GCC or Clang mangled symbol, which gives us a good starting place: We can look for information on the GNU mangling schemes.
Next, look for patterns in the symbol. There are multiple one-number-multiple-letters strings, where the number is the total number of letters in the string; this likely indicates that these are names.
Considering that, we can take the symbol ZN5Gnome5Glade3Xml6createERKSsRKN4Glib7ustringES7, and break it down into:
Z
N
5Gnome
5Glade
3Xml
6create
E
R
K
S
s
R
K
N
4Glib
7ustring
E
S
7
Now, according to the GNU3-4 mangling scheme described in the PDF "Calling Conventions" (pg.38), names are encoded as:
<public name> ::= _Z <qualified name>
<qualified name> ::= N [<simple name>]<sup>∞</sup><sub>2</sub> E
There are a minimum of 2 "simple name" symbols.
<simple name> ::= <name length> <name>
"Name length" is a decimal number indicating the length of "name".
Nested names are listed inwards, with the leftmost one being the outermost.
We can use this to piece together a partial symbol, and its meaning:
Symbol: _ZN5Gnome5Glade3Xml6createE
Means : The symbol's qualified name is "Gnome::Glade::Xml::create".
Note : At least one underscore appears to have been dropped by the error message.
Considering the junk after it, and the name itself, this is a function symbol. So, considering that, we can just feed the symbol to Google, and get a link to the class' reference. According to this link, the function is defined as:
Class : Gnome::Glade::Xml
Section: "Static Public Member Functions"
Full declaration:
static Glib::RefPtr< Xml >
create (const std::string &filename, const Glib::ustring &root=Glib::ustring(),
const Glib::ustring &domain=Glib::ustring())
To double-check, we can determine what the function's mangled name would be, using that parameter list:
static Glib::RefPtr< Xml >
Gnome::Glade::Xml::create (const std::string &filename,
const Glib::ustring &root=Glib::ustring(),
const Glib::ustring &domain=Glib::ustring());
Directly putting this in a simple C++ program (using dummy classes for Glib::RefPtr<T>, Glib::ustring, and Gnome::Glade::Xml), then outputting typeid(Gnome::Glade::Xml::create).name() to cout didn't generate the correct symbol, which suggests a change in either the mangling scheme or the ABI. More specifically, std::string was mangled as NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE, instead of the expected Ss. After a bit of digging around, I discovered that this is due to a change in GCC 5.1 and later versions, where the macro _GLIBCXX_USE_CXX11_ABI indicates to use the new string (and new name) instead of the old one. This gives a likely indication of the cause of the problem, as well (see the end of this post).
So, considering this, it would be best to mangle the function's name by hand, using the old scheme, and see if it matches the symbol.
<public name> ::= <simple or qualified name> [<parameter type>]<sup>∞</sup><sub>1</sub>
There is a minimum of 1 "parameter type" symbols.
Name : Gnome::Glade::Xml::create
Parameters:
const std::string& : RKSs
"RK" is "Reference (R), const (K)", and "Ss" is a special symbol for std::string.
const Glib::ustring& : RK4Glib7ustringE
"RK" is followed by the type's "qualified name".
const Glib::ustring& : RK4Glib7ustringE
As the third parameter is a duplicate of the third, it uses abbreviation rules, where Sx_ is an abbreviated symbol. According to the PDF, each user-defined type name, namespace name, and non-simple type is assigned an abbreviation, but the entity name itself is not. Therefore...
S0_ : 5Gnome
S1_ : 5Glade
S2_ : 3Xml
S3_ : Ss
S4_ : RKSs
S5_ : 4Glib
S6_ : 7ustring
S7_ : RK4Glib7ustringE
And thus, the third parameter is S7_. Considering this, the final symbol is:
Name : _ZN5Gnome5Glade3Xml6createE
Parameter list: RKSsRKN4Glib7ustringES7_
Parameters:
RKSs : const std::string&
RKN4Glib7ustringE : const Glib::ustring&
S7_ : const Glib::ustring&
Symbol : _ZN5Gnome5Glade3Xml6createERKSsRKN4Glib7ustringES7_
Two underscores were apparently dropped somewhere, one on each end.
Feeding this to the utility site Demangler.com results in the following demangled symbol:
Gnome::Glade::Xml::create(std::string const&, Glib::ustring const&, Glib::ustring const&)
As the PDF states that the return type isn't included in the mangling scheme for normal functions, this appears to be correct.
Now, as mentioned above, the ABI was changed, resulting in changes to the mangling scheme and/or the library typenames. So, to check this, I did a little testing.
// main.cpp
//#undef _GLIBCXX_USE_CXX11_ABI
//#define _GLIBCXX_USE_CXX11_ABI 0
//#include <iostream>
//#include <typeinfo>
#include <string>
namespace Glib {
template<typename T>
class RefPtr {};
class ustring {};
}
namespace Gnome {
namespace Glade {
class Xml {
public:
static Glib::RefPtr< Xml >
create (const std::string &filename,
const Glib::ustring &root=Glib::ustring(),
const Glib::ustring &domain=Glib::ustring());
};
}
}
Glib::RefPtr< Gnome::Glade::Xml >
Gnome::Glade::Xml::create (const std::string &filename,
const Glib::ustring &root /*=Glib::ustring()*/,
const Glib::ustring &domain /*=Glib::ustring()*/) {
return Glib::RefPtr<Gnome::Glade::Xml>();
}
int main() {
// std::cout << typeid(const std::string&).name() << std::endl;
// std::cout << typeid(Gnome::Glade::Xml::create).name() << std::endl;
// std::cout << typeid(std::string).name() << std::endl;
}
By taking this code, I first used typeid to output the function symbol, then commented out the first two #includes and the body of main(), compiled the file with the -c compiler option, and output the symbol list with nm main.o. While typeid didn't match the symbol, the names displayed by nm were:
// With macros commented out:
_ZN5Gnome5Glade3Xml6createERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKN4Glib7ustringESD_
// With macros active:
_ZN5Gnome5Glade3Xml6createERKSsRKN4Glib7ustringES7_
As the second one is identical to the symbol mentioned in the error message, this indicates that the mangling scheme is still the same, and thus the solution to the problem is:
Either the object files you're attempting to link were compiled with different versions of GCC (or whichever GCC-compatible compiler you were using), or one was compiled with the _GLIBCXX_USE_CXX11_ABI macro set to 0 and the other wasn't.

I had the same problem trying to install flycapture on arch linux. Eventually I figured out there is a more recent version of flycapture available (2.11.3.121) that doesn't have that problem.

Related

How to detect if global variable is a string in LLVM?

In earlier releases of llvm/clang I was able to detect whether global variable was a string by using ie. the GlobalVar->getName() function and checking whether it ends with ".str". I've tried this in the llvm/clang 13 and 14 and it seems that all the names I'm getting are mangled names. Am I missing something?
For example, I have this basic C source code:
//compiled with: clang.exe -std=c99 helloCC.c -o helloCC.exe -mllvm -my_get_strings=1 -flegacy-pass-manager
#include <stdio.h>
char *xmy1 = "hello world";
int main(int argc, char *argv[]) {
printf("%s", xmy1);
return 0;
}
I've manually edited the llvm/clang code too trigger my function as one of the pass (clang executed with "-flegacy-pass-manager" and I've added my pass to PassManagerBuilder.cpp int the void PassManagerBuilder::populateModulePassManager(legacy::PassManagerBase &MPM) function.
Anyway my runOnModule handler executes, iterates over global variables (M.global_being() to M.global_end()) and all the names got by GlobalVar->getName() seems to be mangled:
found global = "??_C#_0M#LACCCNMM#hello?5world?$AA#"
Obviously now my previous theory to detect whether this is a string or not doesn't work. Is there any other better function to detect whether a global is a string / or I am doing something wrong?
I've tried demangling the name, well I can demangle it but I still don't know how to verify whether this is a string or nor. Is there any LLVM function for it?
Well, the main question here is what do you mean by "global variable is string". If you're meaning C-style strings, then you'd just take initializer (which is Constant) and check if this is a C-style string using isCString method (https://llvm.org/doxygen/classllvm_1_1ConstantDataSequential.html#aecff3ad6cfa0e4abfd4fc9484d973e7d)

Does the using declaration allow for incomplete types in all cases?

I'm a bit confused about the implications of the using declaration. The keyword implies that a new type is merely declared. This would allow for incomplete types. However, in some cases it is also a definition, no? Compare the following code:
#include <variant>
#include <iostream>
struct box;
using val = std::variant<std::monostate, box, int, char>;
struct box
{
int a;
long b;
double c;
box(std::initializer_list<val>) {
}
};
int main()
{
std::cout << sizeof(val) << std::endl;
}
In this case I'm defining val to be some instantiation of variant. Is this undefined behaviour? If the using-declaration is in fact a declaration and not a definition, incomplete types such as box would be allowed to instantiate the variant type. However, if it is also a definition, it would be UB no?
For the record, both gcc and clang both create "32" as output.
Since you've not included language-lawyer, I'm attempting a non-lawyer answer.
Why should that be UB?
With a using delcaration, you're just providing a synonym for std::variant<whatever>. That doesn't require an instantiation of the object, nor of the class std::variant, pretty much like a function declaration with a parameter of that class doesn't require it:
void f(val); // just fine
The problem would occur as soon as you give to that function a definition (if val is still incomplete because box is still incomplete):
void f(val) {}
But it's enough just to change val to val& for allowing a definition,
void f(val&) {}
because the compiler doesn't need to know anything else of val than its name.
Furthermore, and here I'm really inventing, "incomplete type" means that some definition is lacking at the point it's needed, so I expect you should discover such an issue at compile/link time, and not by being hit by UB. As in, how can the compiler and linker even finish their job succesfully if a definition to do something wasn't found?

How to stop clang AST misinterpreting this type of function declaration as a variable declaration?

I am using clang's abstract syntax tree generation to generate an AST for some source files. It maps out normal functions great, however it trips up on some functions, mislabeling them as variable declarations. When it does this it waits for a semicolon to finish this declaration and so does not map out the rest of the source file following the problem function. Is there a way to make clang realize that it's a function definition, not a variable declaration?
I put a semicolon after the function definition and doing that makes clang ignore the contents of the function, but at least it generates nodes for the code following it in the source file. I'm using the prophy python interface to interact with clang in my scripts, but ran clang manually and found the same thing.
This is an example of a function that clang does map:
int killProcess(int pid)
{
int ret=1;
HANDLE pHandle;
if ((pHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid)) != NULL)
if(!TerminateProcess(pHandle,0)) {
ret=0;
CloseHandle(pHandle);
}
return ret;
}
This is an example of a function which clang thinks is a variable declaration and ignores everything after it if there is no semicolon after the closing brace:
DWORD WINAPI listProcessesThread(LPVOID param)
{
char sendbuf[IRCLINE];
LPROC lproc = *((LPROC *)param);
LPROC *lprocp = (LPROC *)param;
lprocp->gotinfo = TRUE;
sprintf(sendbuf,"[PROC]: Listing processes:");
if (!lproc.silent) irc_privmsg(lproc.sock,lproc.chan,sendbuf,lproc.notice);
if (listProcesses(lproc.sock,lproc.chan,lproc.notice,NULL, FALSE, lproc.full) == 0)
sprintf(sendbuf,"[PROC]: Process list completed.");
else
sprintf(sendbuf,"[PROC]: Process list failed.");
if (!lproc.silent) irc_privmsg(lproc.sock, lproc.chan, sendbuf, lproc.notice);
addlog(sendbuf);
clearthread(lproc.threadnum);
ExitThread(0);
}
The expected results would be that clang knows that this is a function and generates a corresponding AST, however it doesn't. It constructs a VAR_DECL node with the spelling "WINAPI" instead of a "FUNCTION_DECL" node. The error it gives upon running "clang -cc1 -ast-dump processes2.cpp" is:
`-VarDecl 0x5625ad7ab2e0 col:7 invalid WINAPI 'int'
1 error generated.
At the end of its log. The abstract syntax tree up until this point is generated and displayed.
NB: I do not have WINAPI library installed because I am working on a Ubuntu machine.

Can I get bison to make yytname externally visible?

Bison generates at table of tag names when processing my grammar, something like
static const char *const yytname[] =
{
"$end", "error", "$undefined", "TAG", "SCORE",
...
}
The static keyword keeps yytname from being visible to other parts of the code.
This would normally be harmless, but I want to format my own syntax error messages instead of relying on the ones provided to my yyerror function.
My makefile includes the following rule:
chess1.tab.c: chess.tab.c
sed '/^static const.*yytname/s/static//' $? > $#
This works, but it's not what I'd call elegant.
Is there a better way to get at the table of tag names?
You can export the table using a function which you add to your parser file:
%token-table
%code provides {
const char* const* get_yytname(void);
}
...
%%
...
%%
const char* const* get_yytname(void) { return yytname; }
You probably also want to re-export some of the associated constants.
Alternatively, you could write a function which takes a token number and returns the token name. That does a better job of encapsulation; the existence of the string table and its precise type are implementation details.

Parse data structures clang/LLVM

I was wondering what is the best solution in order to parse and obtain data structures from C sources files. Suppose that I have:
typedef int M_Int;
typedef float* P_Float;
typedef struct Foo {
M_Int a;
P_Float p_f;
} Foo;
What is the best way to unfold the data structures in order to get the primitives of both variables a and p_f of struct Foo?
Parsing the AST, for very simple examples, could be the best way, but when the code becomes more complex, maybe it's better to work in a more low-level way with IR code?
You can use llvm debug info to grab the information you need. If you compile the C code with -g option, it generates debug info which contains all the information. Understanding llvm debuginfo is tricky mostly because there is not much documentation about their structure and how to access them. Here are some links:
1) http://llvm.org/docs/SourceLevelDebugging.html
2) Here is a link to a project that I am working on which uses debug info. This might not be too useful as there is not much documentation but it might be useful to see the usage of the debuginfo classes. We are trying to get field names for all pointer parameters (including field names in case of structure parameter) of a C function. All of the code related to debuginfo access is in this file: https://github.com/jiten-thakkar/DataStructureAnalysis/blob/dsa_llvm3.8/lib/dsaGenerator/DSAGenerator.cpp
To find the underlying types, the AST is a good level to work at. Clang can automate and scale this process with AST Matchers and Callbacks, used in conjunction with libtooling. For example, the AST matcher combination
fieldDecl( hasType( tyoedefType().bind("typedef") ) ).bind("field")
will match fields in C structs that are declared with a typedef instead of a built-in type. The bind() calls make AST nodes accessible to a Callback. Here's a Callback whose run() method gets the underlying type of the field declaration:
virtual void run(clang::ast_matchers::MatchFinder::MatchResult const & result) override
{
using namespace clang;
FieldDecl * f_decl =
const_cast<FieldDecl *>(result.Nodes.getNodeAs<FieldDecl>("field"));
TypedefType * tt = const_cast<TypedefType *>(
result.Nodes.getNodeAs<TypedefType>("typedef"));
if(f_decl && tt) {
QualType ut = tt->getDecl()->getUnderlyingType();
TypedefNameDecl * tnd = tt->getDecl();
std::string struct_name = f_decl->getParent()->getNameAsString();
std::string fld_name = f_decl->getNameAsString();
std::string ut_name = ut.getAsString();
std::string tnd_name = tnd->getNameAsString();
std::cout << "Struct '" << struct_name << "' declares field '"
<< fld_name << " with typedef name = '" << tnd_name << "'"
<< ", underlying type = '" << ut_name << "'" << std::endl;
}
else {
// error handling
}
return;
} // run
Once this is put into a Clang Tool and built, running
typedef-report Foo.h -- # Note two dashes
produces
Struct 'Foo' declares field 'a' with typedef name = 'M_Int', underlying type = 'int'
Struct 'Foo' declares field 'p_f' with typedef name = 'P_Float', underlying type = 'float *'
I put up a full working example app in a Code Analysis and Refactoring Examples with Clang Tools project (see apps/TypedefFinder.cc).

Resources