I'm developping an application on Windows using G++/MinGW. When my application crash, I would like to log the stacktrace. I understand that I cannot use "SymGetSymFromAddr" function to retrieve the method name because it works only on executable built with Visual Studio (PDB format).
Therefore, my idea is to print only the debug symbol addresses and then use "addr2line" tool to retrieve the method name / line number.
Here is the code to print the stacktrace method name addresses:
LONG WINAPI signalHandler(EXCEPTION_POINTERS* exceptionInfo) {
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
CONTEXT* context = exceptionInfo->ContextRecord;
SymInitialize(process, nullptr, true);
STACKFRAME frame = {};
frame.AddrPC.Offset = context->Rip;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrStack.Offset = context->Rsp;
frame.AddrStack.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context->Rbp;
frame.AddrFrame.Mode = AddrModeFlat;
std::stringstream ss;
while (StackWalk(IMAGE_FILE_MACHINE_AMD64, process, thread, &frame, context, nullptr, SymFunctionTableAccess, SymGetModuleBase, nullptr)) {
std::string moduleName = "[unknown]";
DWORD64 moduleBase = SymGetModuleBase(process, frame.AddrPC.Offset);
char moduleBuffer[MAX_PATH];
if (moduleBase && GetModuleFileNameA((HINSTANCE)moduleBase, moduleBuffer, MAX_PATH)) {
moduleName = moduleBuffer;
}
void* instructionShift = (char*)frame.AddrPC.Offset;
ss << "\t[bt]\t> " << "addr2line -f -e " << moduleName << " " << instructionShift << std::endl;
}
SymCleanup(process);
Logger::instance().logError(ss.str());
return EXCEPTION_EXECUTE_HANDLER;
}
Here is an example of result when I've got an application crash:
[bt] > addr2line -f -e C:\msys64\home\greg\project\myApp.exe 0x7ff611d13faf
[bt] > addr2line -f -e C:\msys64\home\greg\project\myApp.exe 0x7ff611d13763
[bt] > addr2line -f -e C:\msys64\home\greg\project\myApp.exe 0x7ff611daf325
[bt] > addr2line -f -e C:\WINDOWS\System32\USER32.dll 0x7ffde66f1c4c
[bt] > addr2line -f -e C:\WINDOWS\System32\USER32.dll 0x7ffde66f189e
[bt] > addr2line -f -e C:\WINDOWS\SYSTEM32\opengl32.dll 0x7ffd864e3554
[bt] > addr2line -f -e C:\WINDOWS\System32\USER32.dll 0x7ffde66f1c4c
[bt] > addr2line -f -e C:\WINDOWS\System32\USER32.dll 0x7ffde66f0ea6
[bt] > addr2line -f -e C:\msys64\home\greg\project\myApp.exe 0x7ff611db218f
[bt] > addr2line -f -e C:\msys64\home\greg\project\myApp.exe 0x7ff611d13a8f
[bt] > addr2line -f -e C:\msys64\home\greg\project\myApp.exe 0x7ff611d114c6
[bt] > addr2line -f -e C:\WINDOWS\System32\KERNEL32.DLL 0x7ffde57b54e0
[bt] > addr2line -f -e C:\WINDOWS\SYSTEM32\ntdll.dll 0x7ffde788485b
Unfortunately, when I execute the "addr2line" command, I always get the following result:
??
??:0
I well compiled my application with debug option (-g). Therefore, why the method name is not returned by "addr2line" tool ? Or maybe it is not possible to get correct addresses with "StackWalk" function on application built with G++ ?
Related
I have a function like this
void smbProcess(){
string smbTargetIP;
cout<<"Target IP: ";
cin>>smbTargetIP;
string commandSmb_S = "crackmapexec smb " + smbTargetIP;
int smbLength = commandSmb_S.length();
char commandSmb_C[smbLength + 1];
strcpy(commandSmb_C, commandSmb_S.c_str());
system("xterm -hold -e commandSmb_C");
}
I want to create a new terminal and run my command (like this "crackmapexec smb 192.168.1.0/24"). But it doesn't work. When I try this, it works
system("xterm -hold -e date");
These are also doesn't work
system("xterm -hold -e 'commandSmb_C'");
system("xterm -hold -e "commandSmb_C"");
If you know another way to do this it will works too
Add "xterm -hold -e" to commandSmb_S
void smbProcess(){
string smbTargetIP;
cout<<"Target IP: ";
cin>>smbTargetIP;
string commandSmb_S = "xterm -hold -e crackmapexec smb " + smbTargetIP;
int smbLength = commandSmb_S.length();
char commandSmb_C[smbLength + 1];
strcpy(commandSmb_C, commandSmb_S.c_str());
system(commandSmb_C);
}
I am a C++ programmer. I wanted to automate the task of compiling, running and debugging of a program into one neat PowerShell script. But it unexpectedly throws unrelated error which I don't know why.
The program takes C++ file(s) as input, produces a compiled .exe file and runs the program, all at once. It also takes other little debugging options.
if (!($args.count -ge 1)) {
Write-Host "Missing arguments: Provide the filename to compile"
exit
}
$isRun = 1
$EXE_NM = [IO.Path]::GetFileNameWithoutExtension($args[0])
$GPP_ARGS = "-o " + $EXE_NM + ".exe"
$count = 0
foreach ($op in $args) {
if ($op -eq "-help" -or $op -eq "-?") {
Write-Host "Format of the command is as follows:-"
Write-Host "cpr [filename.cpp] {additional files}"
Write-Host "{-add [compiler options] (all options of -add should be in double quotes altogether)}"
Write-Host "[-d (short for -add -g)] [-nr (do not run automatically)]"
exit
} elseif ($op.Contains(".cxx") -or $op.Contains(".cpp")) {
$op = """$op"""
$GPP_ARGS += " " + $op
} elseif ($op -eq "-add") {
if (($count+1) -ne $args.Count) {
$GPP_ARGS += " " + $args[$count+1]
}
} elseif ($op -eq "-d") {
$GPP_ARGS += " -g"
} elseif ($op -eq "-nr") {
$isRun = 0
}
$count += 1
}
$err = & g++.exe $GPP_ARGS 2>&1
if ($LastExitCode -eq 0) {
if ($isRun -eq 1) {
if ($isDebug -eq 1) {
gdb.exe $EXE_NM
} else {
iex $EXE_NM
}
}
if ($err.length -ne 0) {
Write-Host $err -ForegroundColor "Yellow"
}
} else {
Write-Host "$err" -ForegroundColor "Red"
}
For example: When I try to do cpr.ps1 HCF.cpp it throws the following error:
g++.exe: fatal error: no input files compilation terminated.
I have ensured that the .cpp file exists in the current working directory.
I second the recommendation of using make rather than writing your own build script. A simple re-usable Makefile isn't that difficult to write:
CXX = g++.exe
CPPFLAGS ?= -O2 -Wall
# get all files whose extension begins with c and is at least 2 characters long,
# i.e. foo.cc, foo.cpp, foo.cxx, ...
# NOTE: this also includes files like foo.class, etc.
SRC = $(wildcard *.c?*)
# pick the first file from the above list and change the extension to .exe
APP = $(basename $(word 1, $(SRC))).exe
$(APP): $(SRC)
$(CXX) $(CPPFLAGS) -o $# $<
.PHONY: run
run: $(APP)
#./$(APP)
.PHONY: debug
debug: $(APP)
#gdb $(APP)
.PHONY: clean
clean:
$(RM) $(APP)
make builds the program (if required). make run executes the program after building it. make debug runs the program in gdb. make clean deletes the program.
You can override the default CPPFLAGS by defining an environment variable:
$env:CPPFLAGS = '-g'
make
Here's a terminal command:
awk '/^Mem/ {print $4}' <(free -m)
Here's my code:
class CSystemInfo{
public:
std::string free_ram(){
std::string s;
FILE *in;
char buff[512];
//here is a prepared string (but with an error)
if(!(in = popen("awk '/^Mem/ {print $4 \"\\t\"}' <(free -m)","r"))){
return "";
}
while(fgets(buff, sizeof(buff), in)!=NULL){
cout << s;
s=s+buff;
}
pclose(in);
return s;
}
};
CSystemInfo info;
std::string ram = info.free_ram();
cout << ram;
The above code, when run, returns this message:
sh: 1: Syntax error: "(" unexpected
How can I place the '/' symbol, for this command to work correctly?
Your problem is not in C++. You are invoking your command with popen, and popen runs your command in sh shell, that does not support <() syntax, while in your terminal you are having bash, zsh or any other shell, that does support <() syntax.
Edit: Better choise! Use pipes!
popen("free -m | awk ...")
Original answer, not working!: Try invoking bash in popen:
bash -c "awk '/^Mem/ {print $4}' <(free -m)"
in code:
popen("bash -c \"awk '/^Mem/ {print $4}' <(free -m)\"")
Working on Linux am trying to build a Crash Handler function - so as before crashing we get stack trace in log file -
done some study and came to know,its done either using -g/-rdynamic Flags to generate debug info then use glibc backtrace / backtrace_symbols_fd functions to get stack trace ...
Its not much of use as in my app, am not allowed to use -g/-rdynamic flags ..
so reading further reading
I have build the following code which is not working as expected and in generated log file it ends in following error :
(gdb) Hangup detected on fd 0
error detected on stdin
A debugging session is active.
Inferior 1 [process 6625] will be detached.
Quit anyway? (y or n) [answered Y; input not from terminal]
Detaching from program: /u/vivek/demo/testprg, process 6625
Code:
Register a Crash Handler function at startup as -
struct sigaction act;
memset(&act, 0, sizeof (act));
act.sa_sigaction = ProcessCrash;
sigfillset (&act.sa_mask);
act.sa_flags = SA_SIGINFO;
sigaction (SIGSEGV, &act, NULL);
Following function called when my program receives SIGSEGV signal -
void ProcessCrash( int signal, siginfo_t * siginfo, void *context)
{
cerr <<"** ProcessCrash –Handler Function**" << endl;
ucontext_t *uc = (ucontext_t *)context;
if (signal == SIGSEGV)
fprintf(stderr, "\nGot signal %d, faulty address is %p, "
"from %p\n\n", signal, siginfo->si_addr,
uc->uc_mcontext.gregs[REG_RIP]); // REG_EIP is changed to REG_RIP for –m64 arch.
else
fprintf(stderr, "Got signal %d#92;\n", signal);
// [[ using GDB to pring the stack trace
char gdb[516];
// command 1
//sprintf(gdb, "echo 'where\ndetach' | gdb -q %.256s -pid %d > gdbTest.dump", program_invocation_name, getpid());
// command 2
sprintf(gdb, "(echo \"source Trace.txt\";cat) | gdb -q %.256s -pid %d > gdbTest.dump", program_invocation_name, getpid());
fprintf(stderr, "\n** GDB Command-> %s \n", gdb);
// output of above is
// ** GDB Command-> (echo "source Trace.txt";cat) | gdb -q /u/vivek/demo/testprg -pid 6625 > gdbTest.dump
// Run Either command 1 or command 2 but we get the same result
system(gdb);
// GDB test ]]
// Produce a core dump
abort();
return;
}
Trace.txt contents:
set logging on
where
detach
quit
Please let me know is there a way out of it ... as I am not getting ideas to overcome it ..
Not sure what you intended to do with the (echo \"source Trace.txt\";cat) | part.
Simply using gdb -batch -x Trace.txt -q %.256s -pid %d > gdbTest.dump works fine as far as I can tell.
I am trying to write a program in C (in Linux 64bit with GCC 4.1.2).
int program_instances(char *cmdname)
{
char buf[32], *ret;
char cmdbuf[512];
FILE *cmdpipe;
sprintf(cmdbuf, "/bin/ps -eo comm | /bin/grep -c '%s'",
cmdname);
cmdpipe = popen(cmdbuf, "r");
if (!cmdpipe)
{
return -1;
}
memset(buf, 0, sizeof(buf));
ret = fgets(buf, sizeof(buf), cmdpipe);
pclose(cmdpipe);
if (!ret)
{
return -1;
}
int nr = atoi(buf);
return nr;
}
Tried to debug the issue through gdb but after the line
sprintf(cmdbuf, "/bin/ps -eo comm | /bin/grep -c '%'",cmdname);
The programm is not crossing the above line , throwing the below lines..
Executing new program: /bin/bash
Error in re-setting breakpoint 1: No symbol table is loaded. Use the "file" command.
[New process 2437]
Executing new program: /bin/ps
Please help us to resolve this issue.
Try to compile your code with -g and remove -O [compiler flag]. When optimizing compiler(gcc) changes order of instructions to improve speed. After recompiling attach debugger again.