How to mangle and then demangle a function during LLVM pass? - c++

I have an LLVM pass used to rename functions. Given some source file file.cc, I generate LLVM bitcode as follows:
clang -c -o foo.bc -emit-llvm foo.cc.
I'd like to run an LLVM pass over foo.bc and rename all globals, functions and aliases so that I can output the transformed bitcode to a new file file_renamed.bc, and then link file.bc and file_renamed.bc into a single file, file_linked.bc.
One of my issues I encountered is that simply doing F.setName(F.getName() + "_renamed"), will add the suffix after the mangled name returned by F.getName().
Another issue: I have a function demangle(const std::string &Name) below that successfully demangles Name, but I'm having trouble re-mangling that name.
If there is a better way to rename identifiers in LLVM bitcode, or otherwise link two instances of the same bitcode but still be able to uniquely identify the functions and global variables in each version, feel free to suggest it in your answer.
Here is my LLVM pass. Note that I'm using LLVM 3.4 (it is a dependency for the project I'm working on.)
Headers
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cxxabi.h>
#include <memory>
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/TypeFinder.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/Target/Mangler.h"
Code
using namespace llvm;
namespace {
struct FunctionRename : public ModulePass {
static char ID; // Pass identification
FunctionRename() : ModulePass(ID) {}
bool runOnModule(Module &M) override {
// Rename all globals and references to them
for (auto it = M.global_begin(); it != M.global_end(); ++it)
{...}
// Rename all aliases and references to them
for (auto it = M.alias_begin(); it != M.alias_end(); ++it)
{...}
// Rename all functions and references to them
for (auto &F : M)
{
StringRef Name = F.getName();
if (F.isDeclaration())
continue;
std::string demangled_name = demangle(Name.str());
std::string new_name = rename(demangled_name);
F.setName(mangle(new_name, &F));
F.setLinkage(GlobalValue::WeakAnyLinkage);
}
return true;
}
std::string demangle(const std::string &Name)
{
int status;
char* demangled_name = NULL;
char* cstr_name = new char[Name.length() + 1];
strcpy(cstr_name, Name.c_str());
demangled_name = __cxxabiv1::__cxa_demangle(cstr_name, NULL, NULL, &status);
if (status != 0)
{
errs() << "Demangling operation failed:\n";
switch (status)
{...}
exit(-1);
}
std::string s(demangled_name);
return s;
}
std::string rename(std::string &Name)
{
std::string search_str = std::string("(");
std::string suffix_str = std::string("_renamed");
size_t i = Name.find_first_of(search_str);
if (i == std::string::npos)
Name.append(suffix_str);
else
Name.insert(i, suffix_str);
return Name;
}
/* PROBLEMATIC FUNCTION */
std::string mangle(const std::string &Name, const GlobalValue *GV)
{
SmallString<256> MangledName(StringRef(Name));
Mangler m;
m.getNameWithPrefix((SmallVectorImpl<char>&) MangledName, GV, false, true);
Twine T;
StringRef S = T.toStringRef((SmallVectorImpl<char>&) MangledName);
return S.str();
}
};
}
// Register Pass
char FunctionRename::ID = 0;
static RegisterPass<FunctionRename> X("functionrename", "Function Rename Pass");

You cannot easily mangle the C++ identifiers just from string. You need to have proper C++ AST. In fact, I don't see why you'd need that mangle / demangle thing at all. Since you're working at LLVM IR level you should not bother with language details (like original unmangled name) at all.

Related

How do I fix this c++ expected expression error?

I am making something in c++, it doesn't have any errors visible in Visual Studio code, but when I use g++ to be able to execute it, I get this error:
In file included from Main.cpp:6: In file included from ./Filechange/Filechange.hpp:1: ./Filechange/Filechange.cpp:14:24: error: expected expression
std::thread first ([&wtime,&f,&fn]() mutable {
^ Main.cpp:16:33: error: expected expression
OnFilechange("FileEvent", 0.5, [](char* txt){
^ 2 errors generated.
These are the files:
Main.cpp:
#include <lua.hpp>
#include <iostream>
#include <chrono>
#include <thread>
#include <stdio.h>
#include "Filechange/Filechange.hpp"
void wait(int seconds)
{
std::this_thread::sleep_for(std::chrono::seconds(seconds));
}
int main(int argc, char const *argv[])
{
lua_State *State = luaL_newstate();
OnFilechange("FileEvent", 0.5, [](char* txt){
std::cout << txt << std::endl;
});
lua_close(State);
return 0;
}
Filechange.cpp:
#include <thread>
#include <stdio.h>
#include <stdlib.h>
#include <chrono>
#include <string>
#include <fstream>
char* StringToChar(std::string str){
char* Array = new char[str.length() + 1];
strcpy(Array,str.c_str());
return Array;
}
void OnFilechange(const char *f, float wtime, void (*fn)(char* txt)){
std::thread first ([&wtime,&f,&fn]() mutable {
std::ifstream file(f);
std::string str;
std::string filecontents;
while (std::getline(file,str)){
filecontents += str;
filecontents.push_back('\n');
}
char* LastContents = StringToChar(filecontents);
char* CurrentContents = StringToChar(filecontents);
while (true){
if (wtime != 0){
std::this_thread::sleep_for(std::chrono::milliseconds(int(wtime*1000)));
}
filecontents = "";
while (std::getline(file,str)){
filecontents += str;
filecontents.push_back('\n');
}
CurrentContents = StringToChar(filecontents);
if (strcmp(LastContents, CurrentContents) != 0){
LastContents = StringToChar(filecontents);
fn(StringToChar(filecontents));
}
}
});
}
Filechange.hpp:
#include "Filechange.cpp"
#ifndef FILECHANGE_HPP
#define FILECHANGE_HPP
#include <thread>
#include <stdio.h>
#include <stdlib.h>
#include <chrono>
#include <string>
#include <fstream>
void OnFilechange(const char *f,float wtime,void (*fn)(char txt));
#endif
There's also a extension less file named FileEvent which will change in the runtime using other code files.
The Filechange.cpp and Filechange.hpp are in a folder named "Filechange"
This function:
void OnFilechange(const char *f, float wtime, void (*fn)(char* txt))
expects a function pointer, and a lambda in g++ is not implemented as a function pointer. Instead, you should declare the function to take a std::function, as in:
void OnFilechange(const char *f, float wtime, std::function<void(char *)> fn)
You may also need #include <functional> to get the declaration of std::function.
use -std=c++17 in g++ if possible as g++ defaulted to c++98

How to use Clang LibTooling multiple times

Minimul source that use Clang LibTooling which is a very common way:
#include "pch.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"
#include "clang/Driver/Options.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include <iostream>
using namespace std;
using namespace clang;
using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;
class ExampleVisitor : public RecursiveASTVisitor<ExampleVisitor> {
public:
explicit ExampleVisitor(CompilerInstance *CI) {}
};
class ExampleASTConsumer : public ASTConsumer {
private:
CompilerInstance *CI;
public:
explicit ExampleASTConsumer(CompilerInstance *CI) : CI(CI) {}
virtual void HandleTranslationUnit(ASTContext &Context) {
ExampleVisitor(CI).TraverseDecl(Context.getTranslationUnitDecl());
}
};
class ExampleFrontendAction : public ASTFrontendAction {
public:
virtual std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, StringRef file) {
return std::unique_ptr<ASTConsumer>(new ExampleASTConsumer(&CI));
}
};
void run(int argc, const char **argv, llvm::cl::OptionCategory& tc) {
CommonOptionsParser op(argc, argv, tc);
ClangTool Tool(op.getCompilations(), op.getSourcePathList());
std::cout <<"getSourcePathList.size="<< op.getSourcePathList().size()<<"\n";
int result = Tool.run(newFrontendActionFactory<ExampleFrontendAction>().get());
}
int main(int argc, const char **argv) {
llvm::cl::OptionCategory tc1("c1");
llvm::cl::OptionCategory tc2("c2");
llvm::cl::OptionCategory tc3("c3");
run(argc, argv,tc1);
run(argc, argv,tc2);
run(argc, argv,tc3);
std::cin.get();
return 0;
}
the parameters to debug the application is:
"the_only_source_file_to_scan.cpp" --
which is fine.
The output is (from the method "run" above main()):
getSourcePathList.size=1
getSourcePathList.size=2
getSourcePathList.size=3
The problem is that main() calls run() 3 times with the same above parameter which contains only 1 source file to scan, but each time the size of the source-to-scan list stored in CommonOptionsParser increase by one (every item in the list is the same file input from argv), it just seems to append the source file to scan to the list each time.
Everything above is saved in newly created temporary variables in each run, then how and why does LibTooling keep states of the last run and how to "reset" these states?
use FixedCompilationDatabase could circumvent this problem, it can run multiple clangTool in one process
The above code use CommonOptionsParser, whose code is in
clang\lib\Tooling\CommonOptionsParser.cpp
in the method CommonOptionsParser::init there is:
static cl::list<std::string> SourcePaths(...);
Each invocation will add its sources to this static variable. So it is this local static variable that cause the memory of the previous invocations. In each invocation this local static variable is modified by cl::ParseCommandLineOptions in some unkown way since it is not passed into cl::ParseCommandLineOptions at all. After SourcePaths is modified (i.e. sources of the current invocation are added to SourcePaths which may already contain sources of previous invocations), it is finally copied into a instance variable.
BTW #AbaoZhang's clue helps me find the location, indeed CommonOptionsParser::init use FixedCompilationDatabase interally but not for the above situation.
static cl::list<std::string> SourcePaths(...);
#jw_ Yes This code makes problem.
You can fix this.
for (auto iter = llvm::cl::AllSubCommands->OptionsMap.begin(); iter != llvm::cl::AllSubCommands->OptionsMap.end(); iter++)
{
iter->getValue()->setDefault();
}
for (auto iter = llvm::cl::AllSubCommands->PositionalOpts.begin(); iter != llvm::cl::AllSubCommands->PositionalOpts.end(); iter++)
{
(*iter)->setDefault();
}
for (auto iter = llvm::cl::AllSubCommands->SinkOpts.begin(); iter != llvm::cl::AllSubCommands->SinkOpts.end(); iter++)
{
(*iter)->setDefault();
}

using std::string disables program output

Whenever I use std::string to declare a string variable in c++ it prevents the program from outputting anything. for example:
#include <cstdlib>
#include <iostream>
#include <string>
int main() {
std::cout << "Hello";
// std::string s;
return 0;
}
This will output Hello to the command-line as it should do.
#include <cstdlib>
#include <iostream>
#include <string>
int main() {
std::cout << "Hello";
std::string s;
return 0;
}
This will not output anything (and no errors) since i'm declaring a variable using std::string
I'm using the minGW compiler on a Windows 10 64bit machine

How to compare two strings in c++ and work with default functions?

I am working on my first ever c++ code and i am having some diffuclties the strcmp function couldn't be resolved!! Even though i did in h file: using std::string; I am working with Eclipse, so I did an h and cpp files in the h file i have this :
#include <iostream>
#include <string>
#include <set>
using std::set;
using std::string;
namespace AA{
namespace BB{
typedef enum{
EASY , MEDIUM, HARD
} Difficulty;
class FIRST{
private:
char* name;
Difficulty difficulty;
public:
FIRST(const std::string& name, const Difficulty& difficulty);
FIRST(const FIRST& first) = default;
};
} // end of namespace BB
}
// end of namespace AA
and in the cpp file I did this but i get eror that
Function strcmp could not be resolved 'strcmp' is not a member of 'std'
#include <iostream>
#include <string>
#include <set>
#include "Enigma.h"
#include <stdbool.h>
AA::BB::FIRST(const std::string& name, const Difficulty& difficulty):
difficulty(difficulty), name(name) {
}
bool AA::BB::FIRST::operator==(const FIRST& first) const{
if((difficulty==(FIRST.difficulty))&&(strcmp(name,first.name)==0)){
return true;
}
return false;
}
Why compare with strcmp, when you can make use of the existing == operator:
bool AA::BB::FIRST::operator==(const FIRST& first) const{
if((difficulty == FIRST.difficulty) && (name == first.name)){
return true;
}
return false;
}
Or you could use its compare function which would yield the same result:
bool AA::BB::FIRST::operator==(const FIRST& first) const{
if((difficulty == FIRST.difficulty) && (name.compare(first.name) == 0){
return true;
}
return false;
}
When you want to use a certain function you can go to some reference site, find out which header should be included in order to use this function (<cstring> in this case) and then include it.
You should also figure out the code style you are using. CAPS names are typically only used for macros (because they are evil).
The function strcmp is C. There are no strings as you know them from C++.
See here: http://www.cplusplus.com/reference/cstring/strcmp/
You could do:
#include <string>
int main()
{
std::string name = "Webber";
std::string firstName = "John";
if (strcmp(name.c_str(), firstName.c_str()) == 0)
...
}
This will copy your C++ String to an char-Array

How to convert class object to json string using boost library in C++?

I am fairly new to C++ and I apologise beforehand if you find this very easy.
I have the following files
POST1.h
#ifndef POST1_HH
#define POST1_HH
#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
using namespace std ;
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
#include "DBAccess2.h"
class POST1
{
public:
string TokenNo;
string CommandStatus;
string CommandID;
string CPUID;
string ISEncrypted;
string JSON_Cmnd_String;
void POST_Device_Status(sqliteDB & DB_OBJ);
};
#endif
Below is POST1.cpp
#include <iostream>
#include <sstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "DBAccess2.h"
#include "POST1.h"
using namespace std ;
using boost::property_tree::ptree;
using boost::property_tree::read_json;
using boost::property_tree::write_json;
using boost::property_tree::basic_ptree;
void POST1::POST_Device_Status(sqliteDB & DB_OBJ)
{
POST1 POST_OBJ;
POST_OBJ.TokenNo = "1122";
POST_OBJ.CommandStatus = "0";
POST_OBJ.CommandID = "00";
POST_OBJ.CPUID = "A1234B1234";
POST_OBJ.ISEncrypted = "0";
POST_OBJ.JSON_Cmnd_String = DB_OBJ.dump(DB_OBJ);
}
NOTE:-
(1) sqliteDB is another class declared in a .cpp file.
(2) the output of function dump() is a json string. this get stored into JSON_Cmnd_string.
So, I want to convert the class object into JSON string, How can I do that ?
Do I have to first put these object into a container (like vector or list) and then write it into JSON?
This is not "fairly easy", because C++ doesn't have JSON support.
Neither does Boost:
how to get boost json to use the correct data types
That said, this appears to be what you want:
http://www.boost.org/doc/libs/1_57_0/doc/html/boost_propertytree/tutorial.html
So, I want to convert the class object into JSON string, How can I do that ? Do I have to first put these object into a container (like vector or list) and then write it into JSON?
Yes, you put them into a tree container, namely boost::property_tree::ptree:
Live On Coliru
#include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp>
#include <iostream>
#include <sstream>
using boost::property_tree::ptree;
namespace Entities {
struct POST1 {
std::string TokenNo;
std::string CommandStatus;
std::string CommandID;
std::string CPUID;
std::string ISEncrypted;
};
std::string to_json(POST1 const& o) {
ptree out;
out.put("POST1.TokenNo", o.TokenNo);
out.put("POST1.CommandStatus", o.CommandStatus);
out.put("POST1.CommandID", o.CommandID);
out.put("POST1.CPUID", o.CPUID);
out.put("POST1.ISEncrypted", o.ISEncrypted);
std::ostringstream oss;
boost::property_tree::write_json(oss, out);
return oss.str();
}
}
// ADL trigger; `using Entities::to_json` would be roughly equivalent, but not
// make it clear that ADL is happening
void to_json();
int main() {
Entities::POST1 obj { "1122", "0", "00", "A1234B1234", "0" };
std::cout << to_json(obj);
}
Output:
{
"POST1": {
"TokenNo": "1122",
"CommandStatus": "0",
"CommandID": "00",
"CPUID": "A1234B1234",
"ISEncrypted": "0"
}
}
with boost 1.78.0,you can use this
use this simple way
pt::ptree root;
root.put("POST1 .TokenNo", "1122");
root.put("POST1 .CommandStatus", "0");
root.put("POST1 .CommandID", "00");
root.put("POST1 .CPUID", "A1234B1234");
root.put("POST1 .ISEncrypted", "0");
// Once our ptree was constructed, we can generate JSON on standard output
pt::write_json(std::cout, root);
OUT PUT
{
"POST1": {
"TokenNo": "1122",
"CommandStatus": "0",
"CommandID": "00",
"CPUID": "A1234B1234",
"ISEncrypted": "0"
}
}