How to use addr2line directly in c++ - c++

update: this question cannot fix my need, addr2line source is not only 400 lines source, it's relative with other binutils source, I wanna a light solution to do the "get backtrace line number"
I use following that can get backtrace line number:
addr2line -e /home/roroco/Dropbox/c/ro-c/cmake-build-debug/ex/test_backtrace_with_line_number 0x400d0b
but if I wanna get backtrace all line numbers, I must invoke addr2line cli line by line, it's slow, is there way to get backtrace line number without cli but use pure c++? or other alternative lib can get line number
I know if I see addr2line, I can do this, if has more convenient c++ lib, please tell me
here is my code to get line number with addr2line, I hope pure c++ solution to instead addr2line cli
#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include <zconf.h>
#include "regex"
std::string getexepath() {
char result[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
return std::string(result, (count > 0) ? count : 0);
}
std::string sh(std::string cmd) {
std::array<char, 128> buffer;
std::string result;
std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
if (!pipe) throw std::runtime_error("popen() failed!");
while (!feof(pipe.get())) {
if (fgets(buffer.data(), 128, pipe.get()) != nullptr) {
result += buffer.data();
}
}
return result;
}
void print_backtrace(void) {
void *bt[1024];
int bt_size;
char **bt_syms;
int i;
bt_size = backtrace(bt, 1024);
bt_syms = backtrace_symbols(bt, bt_size);
std::regex re("\\[(.+)\\]");
auto exec_path = getexepath();
for (i = 1; i < bt_size; i++) {
std::string sym = bt_syms[i];
std::smatch ms;
if (std::regex_search(sym, ms, re)) {
std::string addr = ms[1];
std::string cmd = "addr2line -e " + exec_path + " -f -C " + addr;
auto r = sh(cmd);
std::regex re2("\\n$");
auto r2 = std::regex_replace(r, re2, "");
std::cout << r2 << std::endl;
}
}
free(bt_syms);
}
void test_m() {
print_backtrace();
}
int main() {
test_m();
return 0;
}

change addr2line source is so hard and I give up this way,
I receive #500 - Internal Server Error suggestion, addr2line cli can receive multi addrs, so I change my code like following, only run addr2line once
#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include <zconf.h>
#include "regex"
#include "vector"
std::string getexepath() {
char result[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
return std::string(result, (count > 0) ? count : 0);
}
std::string sh(std::string cmd) {
std::array<char, 128> buffer;
std::string result;
std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
if (!pipe) throw std::runtime_error("popen() failed!");
while (!feof(pipe.get())) {
if (fgets(buffer.data(), 128, pipe.get()) != nullptr) {
result += buffer.data();
}
}
return result;
}
void print_backtrace(void) {
void *bt[1024];
int bt_size;
char **bt_syms;
int i;
bt_size = backtrace(bt, 1024);
bt_syms = backtrace_symbols(bt, bt_size);
std::regex re("\\[(.+)\\]");
auto exec_path = getexepath();
std::string addrs = "";
for (i = 1; i < bt_size; i++) {
std::string sym = bt_syms[i];
std::smatch ms;
if (std::regex_search(sym, ms, re)) {
std::string m = ms[1];
addrs += " " + m;
}
}
auto r = sh("addr2line -e " + exec_path + " -f -C " + addrs);
std::cout << r << std::endl;
free(bt_syms);
}
void test_m() {
print_backtrace();
}
int main() {
test_m();
return 0;
}

Related

How to print full frame stack backtrace in C code, like gdb

I'm tring to use program ***to print frame stack *** in C/C++ code.
Below is a demo find form internet:
print call stack in C or C++
#include <cassert>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <iomanip>
#include <cxxabi.h> // __cxa_demangle
#include <elfutils/libdwfl.h> // Dwfl*
#include <execinfo.h> // backtrace
#include <unistd.h> // getpid
using namespace std;
// https://stackoverflow.com/questions/281818/unmangling-the-result-of-stdtype-infoname
std::string demangle(const char* name) {
int status = -4;
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status==0) ? res.get() : name ;
}
std::string debug_info(Dwfl* dwfl, void* ip) {
uintptr_t ip2 = reinterpret_cast<uintptr_t>(ip);
Dwfl_Module* module = dwfl_addrmodule(dwfl, ip2);
char const* name = dwfl_module_addrname(module, ip2);
std::string function_name = name ? demangle(name) : "<unknown>";
int line_num = -1;
char const* file_name;
if (Dwfl_Line* dwfl_line = dwfl_module_getsrc(module, ip2)) {
Dwarf_Addr addr;
file_name = dwfl_lineinfo(dwfl_line, &addr, &line_num, nullptr, nullptr, nullptr);
}
std::stringstream ss;
ss << std::setw(16)<<std::setfill('0') <<ip << ' ' << function_name;
if (file_name)
ss << " at " << file_name << ':' << line_num;
ss << std::endl;
return ss.str();
}
std::string gen_framestack_backtrace() {
// Initialize Dwfl.
Dwfl* dwfl = nullptr;
{
Dwfl_Callbacks callbacks = {};
char* debuginfo_path = nullptr;
callbacks.find_elf = dwfl_linux_proc_find_elf;
callbacks.find_debuginfo = dwfl_standard_find_debuginfo;
callbacks.debuginfo_path = &debuginfo_path;
dwfl = dwfl_begin(&callbacks);
assert(dwfl);
int r;
r = dwfl_linux_proc_report(dwfl, getpid());
assert(!r);
r = dwfl_report_end(dwfl, nullptr, nullptr);
assert(!r);
static_cast<void>(r);
}
// Loop over stack frames.
std::stringstream ss;
{
void* stack[512];
int stack_size = ::backtrace(stack, sizeof stack / sizeof *stack);
for (int i = 0; i < stack_size; ++i) {
ss << i << ": ";
// Works.
ss << debug_info(dwfl, stack[i]);
#if 0
// TODO intended to do the same as above, but segfaults,
// so possibly UB In above function that does not blow up by chance?
void *ip = stack[i];
std::string function;
int line = -1;
char const* file;
uintptr_t ip2 = reinterpret_cast<uintptr_t>(ip);
Dwfl_Module* module = dwfl_addrmodule(dwfl, ip2);
char const* name = dwfl_module_addrname(module, ip2);
function = name ? demangle(name) : "<unknown>";
// TODO if I comment out this line it does not blow up anymore.
if (Dwfl_Line* dwfl_line = dwfl_module_getsrc(module, ip2)) {
Dwarf_Addr addr;
file = dwfl_lineinfo(dwfl_line, &addr, &line, nullptr, nullptr, nullptr);
}
ss << ip << ' ' << function;
if (file)
ss << " at " << file << ':' << line;
ss << std::endl;
#endif
}
}
dwfl_end(dwfl);
return ss.str();
}
void my_func_2() {
std::cout << gen_framestack_backtrace() << std::endl;
std::cout.flush();
}
void my_func_1(double f) {
(void)f;
my_func_2();
}
void my_func_1(int i) {
(void)i;
my_func_2();
}
int main(int argc, char **argv) {
long long unsigned int n;
if (argc > 1) {
n = strtoul(argv[1], NULL, 0);
} else {
n = 1;
}
for (long long unsigned int i = 0; i < n; ++i) {
my_func_1(1); // line 122
my_func_1(2.0); // line 123
}
}
Run:
$ sudo apt install libdw-dev libunwind-dev
$
$ g++ -fno-pie -ggdb3 -O0 -no-pie -o a.out -std=c++11 -Wall -Wextra -pedantic-errors test.cpp -ldw -lunwind -ggdb
$ ./a.out
Result:
0: 000000000x401ab1 stacktrace[abi:cxx11]() at /home/wxq/test/test7.cpp:71
1: 000000000x401c11 my_func_2() at /home/wxq/test/test7.cpp:106
2: 000000000x401ca2 my_func_1(int) at /home/wxq/test/test7.cpp:117
3: 000000000x401d01 main at /home/wxq/test/test7.cpp:128
4: 000x7f3e4ee4dbf6 __libc_start_main at ../csu/libc-start.c:310
5: 000000000x401479 _start at ../csu/libc-start.c:-1
0: 000000000x401ab1 stacktrace[abi:cxx11]() at /home/wxq/test/test7.cpp:71
1: 000000000x401c11 my_func_2() at /home/wxq/test/test7.cpp:106
2: 000000000x401c8f my_func_1(double) at /home/wxq/test/test7.cpp:112
3: 000000000x401d16 main at /home/wxq/test/test7.cpp:129
4: 000x7f3e4ee4dbf6 __libc_start_main at ../csu/libc-start.c:310
5: 000000000x401479 _start at ../csu/libc-start.c:-1
But above solution can not print function arguments
Does any one have solution to print backtrace in C/C++ program, just like gdb bt command?
Just like below command
#0 createObj1 (handle=0x5555559291c0, shimHandle=0x55555595a850) at /home/wxq/setup.cpp:983
#1 0x00007ffff60a3763 in initialize (this=0x55555595a850, config=...)at /home/wxq/test.cpp:197
#2 0x00007ffff60a24f2 in create_extended (setup=0x5555559291c0) at /home/wxq/test.cpp:509
#3 0x0000555555555538 in main (argc=5, argv=0x7fffffffe0e8) at /home/wxq/core_model.cpp:145

How to store command output and exitcode from terminal in a variable

From here I have the code that gives me the command line output and the exit code. Unfortunately I don't understand much of that operator overloading and if I try to rewrite it to the simple code I know (with global variables i.e.) I always get the wrong exit code status of 0.
So how can I modify the following code so I can store the output and the exit code status for future use?
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>
struct CommandResult {
std::string output;
int exitstatus;
friend std::ostream &operator<<(std::ostream &os, const CommandResult &result) {
os << "command exitstatus: " << result.exitstatus << " output: " << result.output;
return os;
}
bool operator==(const CommandResult &rhs) const {
return output == rhs.output &&
exitstatus == rhs.exitstatus;
}
bool operator!=(const CommandResult &rhs) const {
return !(rhs == *this);
}
};
class Command {
public:
/**
* Execute system command and get STDOUT result.
* Like system() but gives back exit status and stdout.
* #param command system command to execute
* #return CommandResult containing STDOUT (not stderr) output & exitstatus
* of command. Empty if command failed (or has no output). If you want stderr,
* use shell redirection (2&>1).
*/
static CommandResult exec(const std::string &command) {
int exitcode = 255;
std::array<char, 1048576> buffer {};
std::string result;
#ifdef _WIN32
#define popen _popen
#define pclose _pclose
#define WEXITSTATUS
#endif
FILE *pipe = popen(command.c_str(), "r");
if (pipe == nullptr) {
throw std::runtime_error("popen() failed!");
}
try {
std::size_t bytesread;
while ((bytesread = fread(buffer.data(), sizeof(buffer.at(0)), sizeof(buffer), pipe)) != 0) {
result += std::string(buffer.data(), bytesread);
}
} catch (...) {
pclose(pipe);
throw;
}
exitcode = WEXITSTATUS(pclose(pipe));
return CommandResult{result, exitcode};
}
};
int main ()
{
std::cout << Command::exec("echo blablub") << std::endl;
}
Here is my code, the global variable is correct in the function but is overwritten afterwards.
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <array>
int exitcode = 555;
std::string exec(const std::string cmd) {
int exitcode = 255;
std::array<char, 128> buffer {};
std::string result;
#ifdef _WIN32
#define popen _popen
#define pclose _pclose
#define WEXITSTATUS
#endif
FILE *pipe = popen(cmd.c_str(), "r");
if (pipe == nullptr) {
throw std::runtime_error("popen() failed!");
}
try {
std::size_t bytesread;
while ((bytesread = fread(buffer.data(), sizeof(buffer.at(0)), sizeof(buffer), pipe)) != 0) {
result += std::string(buffer.data(), bytesread);
}
} catch (...) {
pclose(pipe);
throw;
}
exitcode = WEXITSTATUS(pclose(pipe));
std::cout<<exitcode<<'\n';
return result;
}
int main (){
exec("echo bla");
std::cout<<exitcode<<'\n';
}
Assuming the code provided in the article is correct and does what it should do, it is already doing all you need. The exit code and output are returned from the exec function.
You only have to use the returned CommandResult and access its members:
int main() {
auto result = Command::exec("echo blablub");
std::cout << result.output << "\n":
std::cout << result.exitstatus << "\n";
}

How to use mmap for integer input?

I have coded a program that uses mmap as input to fill a integer 2D vector from a .txt file. The code is part of a larger program and will be submitted to a competition. Is there a way to improve the speed using mmap, or by using a different way all together? Here is the code:
#include <fstream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <iostream>
// for mmap:
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
const char* map_file(const char* fname, size_t& length);
int main()
{
auto start = std::chrono::high_resolution_clock::now();
size_t length;
auto f = map_file("erasmus.in", length);
auto l = f + length;
int i = 0;
bool flag = false;
string lines;
vector<vector<int> > students(10000); //The number of lines is predefined
const char* temp;
while (f && f!=l) {
string element = "";
temp = static_cast<const char*>(memchr(f, '\n', l-f));
for(f = f; f<=temp; f++)
{
if(!isspace(*f))
{
element += *f;
flag = true;
}
if(isspace(*f) && flag == true)
{
flag = false;
int assigned_element = stoi(element);
students[i].push_back(assigned_element);
element = "";
}
}
i++;
temp++;
}
auto finish = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> elapsed1 = finish - start;
FILE* output = fopen("erasmus.out", "w");
for (int i = 0; i < students.size(); i++)
{
for (int j = 0; j < students[i].size(); j++)
{
fprintf(output, "%d ", students[i][j]);
}
fprintf(output, "\n");
}
std::cout << "Elapsed time: " << elapsed1.count() << " s\n";
return 0;
}
void handle_error(const char* msg) {
perror(msg);
exit(255);
}
const char* map_file(const char* directory, size_t& length)
{
int fileDirectory = open(directory, O_RDONLY);
if (fileDirectory == -1)
handle_error("open");
// obtain file size
struct stat sb;
if (fstat(fileDirectory, &sb) == -1)
handle_error("fstat");
length = sb.st_size;
const char* map = static_cast<const char*>(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fileDirectory, 0u));
if (map == MAP_FAILED)
handle_error("mmap");
return map;
}
The file will be executed on a linux system, if this helps to find the optimal answer. At the end of each line of the .txt
there is a space character (' ') and a newline('\n')

Im unsure of why my http server is not reading in a filelocation C++

Im creating a http server in c++. I know that TCPServer.h works and that thing/text.txt exists but for some reason the code doesnt read the text file when I do 127.0.0.1. If you would like TCPServer.h to help help just ask I would be more than happy to send it but I just didnt see a reason to do it
#include "TCPServer.h"
#include <future>
#include <fstream>
#include <WS2tcpip.h>
#include <iostream>
#define MAX_BUF (4096)
#pragma comment (lib, "ws2_32.lib")
char * getLoc(char * c) {
char * ret = (char *)malloc(4096);
ZeroMemory(ret, 4096);
for(int i = 4; i < 4092; i++) {
if (*(c + i) == ' ') {
return ret;
}
else {
*(ret + i - 4) = *(c + i);
}
}
return ret;
}
void doStuff(SOCKET sock) {
char * recieved = (char *)malloc(4096);
recv(sock, recieved, 4096, 0);
char * loc = getLoc(recieved);
std::string fileLocation("thing");
fileLocation += loc;
std::ifstream fil;
fil.open(fileLocation);
char * contents = (char *)malloc(4096);
ZeroMemory(contents, 4096);
fil.read(contents, 4096);
fil.close();
std::cout << fileLocation;
std::string shoot("HTTP/1.1 200 OK\n");
shoot += contents;
std::cout << "\n\n\n" << shoot;
send(sock, shoot.c_str(), 4096, 0);
}
int main() {
TCPServ s;
s.createSock(80);
while (true) {
SOCKET sock = s.listenFor();
std::future <void> f = std::async(doStuff, sock);
}
}

sh not found when executing shell command from C++

I have a function in my C++ program like this:
std::string SysExec::executeAndReturnResult(char* cmd) {
//cout << "[SHELL] : " << cmd << endl;
FILE* pipe = popen(cmd, "r");
if (!pipe)
return "ERROR";
char buffer[128];
std::string result = "";
while (!feof(pipe)) {
if (fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
pclose(pipe);
return result;
}
When I call it
SysExec::executeAndReturnResult("/usr/bin/irsend -d /var/run/lirc/lircd-lirc0 SEND_ONCE Samsung 4");
I get this:
sh: 4: not found
However, if I try to same command from the console, it works fine.
I would like to mention that calling it with a non-numeric argument works with no issue — the following works fine:
SysExec::executeAndReturnResult("irsend -d /var/run/lirc/lircd-lirc0 SEND_ONCE Samsung channel+")
I have tried Google..but to no avail. Can anyone help me understanding the issue?
//edit on request:
my SysExec.h file looks like this:
#include "CompileFlags.h"
/*
* sysexec.h
*
* Created on: Dec 19, 2012
* Author: Shrouk H. Khan / Fingi / root
*/
#ifndef SYSEXEC_H_
#define SYSEXEC_H_
#include<stdio.h>
#include <string>
#include <boost/algorithm/string.hpp>
namespace fingigcc {
class SysExec {
public:
SysExec();
virtual ~SysExec();
static std::string executeAndReturnResult(char* cmd);
static int executeAndForget(char* cmd);
static int execute(char* cmd);
};
} /* namespace fingigcc */
#endif /* SYSEXEC_H_ */
And the corresponding cpp file looks like this:
/*
* SysExec.cpp
*
* Created on: Dec 19, 2012
* Author: Shrouk H. Khan / Fingi / root
*/
#include "../../includes/SysExec.h"
#include "../../includes/Logger.h"
#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
namespace fingigcc {
SysExec::SysExec() {
// TODO Auto-generated constructor stub
}
SysExec::~SysExec() {
// TODO Auto-generated destructor stub
}
std::string SysExec::executeAndReturnResult(char* cmd) {
//cout << "[SHELL] : " << cmd << endl;
FILE* pipe = popen(cmd, "r");
if (!pipe)
return "ERROR";
char buffer[128];
std::string result = "";
while (!feof(pipe)) {
if (fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
pclose(pipe);
return result;
}
int SysExec::executeAndForget(char* cmd) {
//cout << "[SHELL] : " << cmd << endl;
//do not try to log it..infinite loop..
// pid_t pid = fork();
// if (pid < 0) {
// return -1;
// } else if (pid == 0) {
// execl(cmd, (char *) 0);
// } else {
//
// }
system(cmd);
return 0;
}
}
/* namespace fingigcc */