SIGSEGV in DSO, mixed C/C++ - c++

I'm using the SWI-Prolog foreign language interface for C++, attempting to integrate some other resource.
It mostly works, but any attempt to throw an exception result in a SIGSEGV. Exceptions are routinely used in validation of user parameters, and thus are a fundamental part of the interface.
I'm compiling SWI-Prolog from source (via supplied script), and the CXX flags are
-c -O2 -gdwarf-2 -g3 -Wall -pthread -fPIC
I'm using the same flags to compile my C++ code, that is assembled in a .so, dynamically loaded in SWI-Prolog (via dlopen, I think).
Inspection of the stack (via GDB) after the SEGV shows the IP at <+36>, inside __cxa_allocate_exception. Likely __cxa_get_globals#plt isn't accessible.
Dump of assembler code for function __cxa_allocate_exception:
0x00007ffff1d80220 <+0>: push %r12
0x00007ffff1d80222 <+2>: lea 0x80(%rdi),%r12
0x00007ffff1d80229 <+9>: push %rbp
0x00007ffff1d8022a <+10>: mov %r12,%rdi
0x00007ffff1d8022d <+13>: push %rbx
0x00007ffff1d8022e <+14>: callq 0x7ffff1d1de30 <malloc#plt>
0x00007ffff1d80233 <+19>: test %rax,%rax
0x00007ffff1d80236 <+22>: mov %rax,%rbx
0x00007ffff1d80239 <+25>: je 0x7ffff1d802d8 <__cxa_allocate_exception+184>
0x00007ffff1d8023f <+31>: callq 0x7ffff1d1efc0 <__cxa_get_globals#plt>
0x00007ffff1d80244 <+36>: addl $0x1,0x8(%rax)
0x00007ffff1d80248 <+40>: test $0x1,%bl
0x00007ffff1d8024b <+43>: mov %rbx,%rdi
0x00007ffff1d8024e <+46>: mov $0x80,%edx
0x00007ffff1d80253 <+51>: jne 0x7ffff1d803d0 <__cxa_allocate_exception+432>
0x00007ffff1d80259 <+57>: test $0x2,%dil
The only resource I've been able to find that seems pertinent claims
the exception requires a typeinfo lookup
and this could make sense of the SIGSEGV.
But I'm unable to proceed now. Of course, I hope in some magic CXX or LD flag.
Or should I decorate my library entry points (I'm acquainted to Windows declspec(s), I used them extensively to build MFC extension DLLs) or whatever?

When called from Prolog, you can't throw any exceptions into the Prolog kernel. The C++ interface will catch PlException and its subclasses and transform them into Prolog exceptions. All other exceptions must not be allowed to escape your library.
Since SWI Prolog is LGPL, you are probably dynamically linking to it. Therefore, you must ensure that all C++ that are thrown have default visibility on ELF systems.

Related

Offset to code location in release-build of Qt 5.12 project with mingw730 32 bit

I have a Qt-project that includes a massive customer legacy code base (that I'm unfortunately not at liberty to post). Debug builds with qmake/QtCreator work, but release builds crash even before hitting main. My suspicion is some static initialisation. When I run the debugger in Qt Creator, I get a segmentation fault and a disassembly trace. No symbols, no really usable stack trace. Any hints on how to approach this? Can I resolve the process address where the crash occurs to a symbol in my code?
Edit: the disassembly looks like this:
0:000> u
ProgrammName+0x39b40:
00439b40 8b842468010000 mov eax,dword ptr [esp+168h]
00439b47 8384246801000004 add dword ptr [esp+168h],4
00439b4f 89fa mov edx,edi
00439b51 8b00 mov eax,dword ptr [eax]
00439b53 85c0 test eax,eax
00439b55 0f8461f6ffff je ProgrammName+0x391bc (004391bc)
00439b5b 85db test ebx,ebx
00439b5d 8d4801 lea ecx,[eax+1]
0:000> u
ProgrammName+0x39b60:
00439b60 0fb600 movzx eax,byte ptr [eax]
00439b63 0f8ef7000000 jle ProgrammName+0x39c60 (00439c60)
00439b69 84c0 test al,al
00439b6b 750d jne ProgrammName+0x39b7a (00439b7a)
00439b6d e9ee000000 jmp ProgrammName+0x39c60 (00439c60)
00439b72 84c0 test al,al
00439b74 0f8442f6ffff je ProgrammName+0x391bc (004391bc)
00439b7a 83eb01 sub ebx,1
My thinking is that the ProgramName+0xXXXX addresses should somehow be translatable into a symbol somehow.
Ok, found a solution: https://forum.qt.io/topic/2363/solved-how-to-build-release-with-debug-info-mingw/4
Basically it's about building for release, but keeping debug symbols. The addition to my Qt project file was
QMAKE_CXXFLAGS_RELEASE += -g
QMAKE_CFLAGS_RELEASE += -g
QMAKE_LFLAGS_RELEASE =

How to make local labels in GNU GAS ELF output that GDB can break on but not count as functions?

When writing assembly manually with GNU GAS, within a function, I want to set a label such that:
GDB won't treat that label as the function name
I can use b mylabel to break on the label
A similar question for nasm has been asked at: Break at local label using GDB for NASM assembly but I wanted to make it more precise here that I want GNU GAS and ELF output.
E.g. if I defined a normal label mylabel as in:
main.S
.text
.global _start
_start:
/* exit */
mov $60, %rax
mylabel:
mov $0, %rdi
syscall
that does not satisfy me because when GDB reaches the mov $0, %rdi, bt shows mylabel as the function name, and I would like it to be _start instead. In particular, this can break backtraces because GDB can't find the stack frame: How gdb reconstructs stacktrace for C++?
However, if I replace mylabel with .Lmylabel as explained at: Local labels in GNU assembler; gdb printing backtrace as though labels are functions then _start is the function name as desired, but b .Lmylabel fails. nm does not show the symbol at all either.
Does the ELF / DWARF formats support anything that could be used, and is there any way to expose that though GNU GAS?
Tested in Ubuntu 18.10, GDB 8.2, GNU GAS 2.31.1.
I'm not sure if this fits your needs, but you can do this (for a non-PIE binary, so link with -no-pie):
.text
.global _start
_start:
/* exit */
mov $60, %rax
.Lmylabel:
mov $0, %rdi
syscall
.section .rodata
mylabel:
.long .Lmylabel
Then, you can set a breakpoint using break *mylabel (note the *):
(gdb) break *mylabel
Breakpoint 2 at 0x401007: file t.S, line 7.
Since mylabel is more or less a function pointer, GDB does not know anything about it and will ignore it:
Breakpoint 1, _start () at t.S:5
5 mov $60, %rax
(gdb) si
7 mov $0, %rdi
With a linker script, it should be possible to put the mylabel symbol into a section which is not loaded, to reduce run-time overhead.

How to see the code at a certain offset using WinDbg, without dump?

I have an executable running on some client. He reports a crash at mymodule.dll!0xaddr.
Given that I have the executable, a symbol server, a properly set up WinDbg, is there any way to see the code at location 0xaddr without loading a dump or attaching to a running process?
It depends a bit on what "code" is for you...
Start WinDbg
Choose "Open crash dump ...", not "Open executable ..."
Select the EXE or DLL file of your choice, not a DMP file
Set up your symbols
Type ln mymodule.dll!0xaddr to see what symbol is near that address
Type u mymodule.dll!0xaddr to see the assembler code
If the EXE or DLL has PDB information and WinDbg was able to find the PDB, and if the PDB refers to source (e.g. private symbols), you'll get something useful:
0:000> ln 00412510
[...\addressdemo\addressdemo.cpp # 8] (00412510) AddressDemo!main | (00412575) AddressDemo!std::uncaught_exception
Exact matches:
0:000> u 00412510
AddressDemo!main [...\projects\addressdemo\addressdemo.cpp # 8]:
00412510 55 push ebp
00412511 8bec mov ebp,esp
00412513 81ecc0000000 sub esp,0C0h
00412519 53 push ebx
0041251a 56 push esi
0041251b 57 push edi

GDB Debugger cannot use scanf [duplicate]

I'm following these lessons from OpenSecurityTraining.
I've reached the lab part where I've to train myself on a CMU Bomb. They provide a x86_64 compiled CMU Bomb that you can find here to train on : CMU Bomb x86-64 originally from a 32-bit bomb from CMU Labs for
Computer Systems: A Programmer's Perspective (CS:APP) 1st edition.
I had a virtualized 64 bits Elementary OS distribution where I disassembled the CMU Bomb without problems using GDB. Now, I've a 64 bits Ubuntu 14.04 LTS (not virtualized) and when I try to reproduce why I did on my Elementary OS, I get the famous error.
I run these commands :
gdb ./bomb-x64
(gdb) b main
Breakpoint 1 at 0x400dbd: file bomb.c, line 37. -- why bomb.c ?
(gdb) r
...
bomb.c: no such file or directory
Edit : I can create breakpoints on others functions of the CMU Bomb and it works as expected.
Example :
(gdb) b phase_1
Breakpoint 3 at 0x400f00
(gdb) r
Breakpoint 1, 0x0000000000400f00 in phase_1 ()
(gdb) disas
Dump of assembler code for function phase_1:
=> 0x0000000000400f00 <+0>: sub $0x8,%rsp
0x0000000000400f04 <+4>: mov $0x4023b0,%esi
0x0000000000400f09 <+9>: callq 0x401308 <strings_not_equal>
0x0000000000400f0e <+14>: test %eax,%eax
0x0000000000400f10 <+16>: je 0x400f17 <phase_1+23>
0x0000000000400f12 <+18>: callq 0x40140a <explode_bomb>
0x0000000000400f17 <+23>: add $0x8,%rsp
0x0000000000400f1b <+27>: retq
End of assembler dump.
I've heard of ia32-libs but this doesn't do anything more since I'm on 64bits Ubuntu and run a 64bits compiled CMU Bomb, am I wrong ?
Use dir command to set source path
dir /usr/src/debug
in above path. Your code should present.
The executable contains debugging symbols, which indicate the file (and particular line in the file) corresponding to each bit of assembled code. This is what allows you to step through C code in the debugger. The debugging symbols are put there by the compiler (e.g. by using the -g argument to gcc).
If you don't have the C files that were used to compile the executable, the debugger won't be able to show you the C, and you'll be limited to looking at assembly.
(gdb) list
/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/tasks.c: No such file or directory.
(gdb) set substitute-path /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/ C:/Espressif/frameworks/esp-idf-v4.4/

GDB ignores my breakpoints

My test case is so simple that I must be doing something very stupid. I wrote a simple source file test.c:
#include<stdio.h>
int main(int argc,char* argv[]){
printf("1\n");
printf("2\n");
printf("3\n");
return 0;
}
I compiled it with gcc -g test.c and started GDB with gdb a.out. Then I created a breakpoint in main with break main and ran it with run(also tried with start) - but GDB simply ignored my breakpoint!
This is the shell session of me trying to compile test.c and run GDB:
[idanarye#idanarye_lg gdbtest]$ gcc -g test.c
[idanarye#idanarye_lg gdbtest]$ gdb a.out
GNU gdb (GDB) 7.6.1
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/idanarye/gdbtest/a.out...done.
(gdb) break main
Breakpoint 1 at 0x40050f: file test.c, line 4.
(gdb) run
Starting program: /home/idanarye/gdbtest/a.out
1
2
3
During startup program exited normally.
(gdb)
What in the world am I doing wrong here?
I'm running a 64bit Arch Linux. My GCC version is 4.8.2.
UPDATE
Here is the result of disas main:
Dump of assembler code for function main:
0x0000000000400500 <+0>: push %rbp
0x0000000000400501 <+1>: mov %rsp,%rbp
0x0000000000400504 <+4>: sub $0x10,%rsp
0x0000000000400508 <+8>: mov %edi,-0x4(%rbp)
0x000000000040050b <+11>: mov %rsi,-0x10(%rbp)
0x000000000040050f <+15>: mov $0x4005c4,%edi
0x0000000000400514 <+20>: callq 0x4003e0 <puts#plt>
0x0000000000400519 <+25>: mov $0x4005c6,%edi
0x000000000040051e <+30>: callq 0x4003e0 <puts#plt>
0x0000000000400523 <+35>: mov $0x4005c8,%edi
0x0000000000400528 <+40>: callq 0x4003e0 <puts#plt>
0x000000000040052d <+45>: mov $0x0,%eax
0x0000000000400532 <+50>: leaveq
0x0000000000400533 <+51>: retq
End of assembler dump.
UPDATE
No idea how or why, but it works now. Probably a system update fixed it...
(curated from comments)
You do not appear do be doing anything wrong; It appears to be GDB's fault.
The message During startup program exited normally. is anomalous, the correct one being Program exited normally.. It suggests GDB failed to insert a breakpoint in main() or the traced program's call to ptrace(PT_TRACE_ME, 0, 0, 0) failed. The program thus ran without being stopped, and it exited while GDB was only expecting it to start up and stop at exec(). Can you run gdb under strace while doing your example and grep strace's log for any failed ptrace calls?
You would do so with strace -f -o syscall.txt gdb ./a.out.
As of right now a stop-gap measure appears to be to run GDB as root.
I encountered a similar problem and in my case the thing was that my program was forking itself. So basically, my code looked like this:
#include <string>
#include <iostream>
#include "func.hpp"
using namespace std;
int main(int argc, char **argv)
{
if(argc <3)
{
printf("\n %s IP PORT\n",argv[0]);
printf("e.g. %s 10.32.129.77 6379\n",argv[0]);
printf("\n Going to run on the default server and port\n");
string command{argv[0]};
command+=" 10.32.129.77 6379";
printf("\nCommand: %s\n",command.c_str());
system(command.c_str());
exit(0);
}
func();
}
I was creating a breakpoint where "func" function was being called. However, I unknowingly wasn't passing the correct arguments and as a result my program forked itself with correct arguments. So basically "func" was now being called from the child process and as it turns out gdb doesn't set the breakpoints at the child process and that's why the breakpoint was not being hit.
I had this same problem. It was intermittent and drove me nuts.
Then I found I did a dumb thing. I had been running the program from the command line, and it had a bunch of arguments.
So, I copied the command line with the mouse-copy-paste buffer.
Then started: gdb Program
Then did: break man
Then did: -PASTE-FROM-MOUSE-
It never stopped, until I realized that I had pasted too much of the command line:
"--option=c ... |& tee LOG"
It looked like an intermittent problem, until I realized it was a brain bug.
Hope this helps someone. The command line redirect - did something in GDB, no clue what (other than ignore breakpoints).