Getting better debug when Linux crashes in a C programme - c

We have an embedded version of Linux kernel running on a MIPs core. The Programme we have written runs a particular test suite. During one of the stress tests (runs for about 12hrs) we get a seg fault. This in turn generates a core dump.
Unfortunately the core dump is not very useful. The crash is in some system library that is dynamically linked (probably pthread or glibc). The backtrace in the core dump is not helpful because it only shows the crash point and no other callers (our user space app is built with -g -O0, but still no back trace info):
Cannot access memory at address 0x2aab1004
(gdb) bt
#0 0x2ab05d18 in ?? ()
warning: GDB can't find the start of the function at 0x2ab05d18.
GDB is unable to find the start of the function at 0x2ab05d18
and thus can't determine the size of that function's stack frame.
This means that GDB may be unable to access that stack frame, or
the frames below it.
This problem is most likely caused by an invalid program counter or
stack pointer.
However, if you think GDB should simply search farther back
from 0x2ab05d18 for code which looks like the beginning of a
function, you can increase the range of the search using the `set
heuristic-fence-post' command.
Another unfortunate-ness is that we cannot run gdb/gdbserver. gdb/gdbserver keeps breaking on __nptl_create_event. Seeing that the test creates threads, timers and destroys then every 5s it is almost impossible to sit for a long time hitting continue on them.
EDIT:
Another note, backtrace and backtrace_symbols is not supported on our toolchain.
Hence:
Is there a way of trapping seg fault and generate more backtrace data, stack pointers, call stack, etc.?
Is there a way of getting more data from a core dump that crashed in a .so file?
Thanks.

GDB can't find the start of the function at 0x2ab05d18
What is at that address at the time of the crash?
Do info shared, and find out if there is a library that contains that address.
The most likely cause of your troubles: did you run strip libpthread.so.0 before uploading it to your target? Don't do that: GDB requires libpthread.so.0 to not be stripped. If your toolchain contains libpthread.so.0 with debug symbols (and thus too large for the target), run strip -g on it, not a full strip.
Update:
info shared produced Cannot access memory at address 0x2ab05d18
This means that GDB can not access the shared library list (which would then explain the missing stack trace). The most usual cause: the binary that actually produced the core does not match the binary you gave to GDB. A less common cause: your core dump was truncated (perhaps due to ulimit -c being set too low).

If all else fails run the command using the debugger!
Just put "gdb" in form of your normal start command and enter "c"ontinue to get the process running. When the task segfaults it will return to the interactive gdb prompt rather than core dump. You should then be able to get more meaningful stack traces etc.
Another option is to use "truss" if it is available. This will tell you which system calls were being used at the time of the abend.

Related

gdb core dump warning: Can't open file /memfd:magicringbuffer (deleted) during file-backed mapping note processing

I implemented a magic ring buffer (MRB) on linux using memfd_create, ftruncate, mmap, and munmap. The fd returned by memfd_create gets close()'d after the buffer is fully constructed. The MRB itself runs and works perfectly fine.
The problem:
One tries to create a core-file on a process running this MRB with gcore.
They then try to use gdb <executable> -c <core-file>
gdb then prints a warning:
warning: Can't open file /memfd:magicringbuffer (deleted) during file-backed mapping note processing
Additional notes:
"magicringbuffer" is the string passed as the name parameter in memfd_create(const char *name, unsigned int flags);
built and run on CentOS version 7
Questions:
What does this warning exactly mean? What causes it? Is it because the "file" is virtual? or because it was close()'d?
What are the implications of it? Could it lead to missing debug symbols? The <executable> is indeed a binary with debug symbols
I tried to look for an answer on the internet, but I found nothing satisfactory.
GDB is trying to reconstruct the virtual address space of the former process, at the time of the core dump, as accurately as possible. This includes re-creating all mmap regions. The message means simply that GDB tried, and failed, to re-create the mmap region that was backed by the memfd. IIRC, the annotation in the core file that tells GDB that an mmap region existed -- the "file-backed mapping note" -- was designed before memfd_create was a thing, and so GDB doesn't know it should be calling memfd_create() instead of regular old open() for this one. And even if it did, it wouldn't be able to recover access to the original memfd area (which might be completely gone by the time you get around to debugging from the core dump).
The practical upshot of this is that, while debugging from the core dump, you won't be able to look at the contents of memory within your magic ring buffer. Debug symbols, however, should be unaffected.
This is arguably a bug in either the kernel or gcore (not sure which); the contents of memfd-backed memory regions should arguably be dumped into the core file like MAP_ANONYMOUS regions, rather than generating file-backed mapping notes.

C malloc "can't allocate region" error, but can't repro with GDB?

How can I debug a C application that does not crash when attached with gdb and run inside of gdb?
It crashes consistently when run standalone - even the same debug build!
A few of us are getting this error with a C program written for BSD/Linux, and we are compiling on macOS with OpenSSL.
app(37457,0x7000017c7000) malloc: *** mach_vm_map(size=13835058055282167808) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
ERROR: malloc(buf->length + 1) failed!
I know, not helpful.
Recompiling the application with -g -rdynamic gives the same error. Ok, so now we know it isn't because of a release build as it continues to fail.
It works when running within a gdb debugging session though!!
$ sudo gdb app
(gdb) b malloc_error_break
Function "malloc_error_break" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (malloc_error_break) pending.
(gdb) run -threads 8
Starting program: ~/code/app/app -threads 8
[New Thread 0x1903 of process 45436]
warning: unhandled dyld version (15)
And it runs for hours. CTRL-C, and run ./app -threads 8 and it crashes after a second or two (a few million iterations).
Obviously there's an issue within one of the threads. But those workers for the threads are pretty big (a few hundred lines of code). Nothing stands out.
Note that the threads iterate over loops of about 20 million per second.
macOS 10.12.3
Homebrew w/GNU gcc and openssl (linking to crypto)
Ps, not familiar with C too much - especially any type of debugging. Be kind and expressive/verbose in answers. :)
One debugging technique that is sometimes overlooked is to include debug prints in the code, of course it has it's disadvantages, but also it has advantages. A thing you must keep in mind though in the face of abnormal termination is to make sure the printouts actually get printed. Often it's enough to print to stderr (but if that doesn't make the trick one may need to fflush the stream explicitly).
Another trick is to stop the program before the error occurs. This requires you to know when the program is about to crash, preferably as close as possible. You do this by using raise:
raise(SIGSTOP);
This does not terminate the program, it just suspends execution. Now you can attach with gdb using the command gdb <program-name> <pid> (use ps to find the pid of the process). Now in gdb you have to tell it to ignore SIGSTOP:
> handle SIGSTOP ignore
Then you can set break-points. You can also step out of the raise function using the finish command (may have to be issued multiple times to return to your code).
This technique makes the program have normal behaviour up to the time you decide to stop it, hopefully the final part when running under gdb would not alter the behavior enuogh.
A third option is to use valgrind. Normally when you see these kind of errors there's errors involved that valgrind will pick up. These are accesses out of range and uninitialized variables.
Many memory managers initialise memory to a known bad value to expose problems like this (e.g. Microsoft's CRT will use a range of values (0xCD means uninitialised, 0xDD means already free etc).
After each use of malloc, try memset'ing the memory to 0xCD (or some other constant value). This will allow you to identify uninitialised memory more easily with the debugger. don't use 0x00 as this is a 'normal' value and will be harder to spot if it's wrong (it will also probably 'fix' your problem).
Something like:
void *memory = malloc(sizeof(my_object));
memset(memory, 0xCD, sizeof(my_object));
If you know the size of the blocks, you could do something similar before free (this is sometimes harder unless you know the size of your objects, or track it in some way):
memset(memory, 0xDD, sizeof(my_object));
free(memory);

Analyzing Core dump for memory leak

I have several core dump files created by manually killing a memory leaking process. I'm trying to open it with GDB, however gdb reports that (no debuggung symbols found). From what I understand, that means that the program was compiled without -g option, which is correct, and because of that, GDB has nothing to catch. I however, want to only open the core dump file, I need to read it in order to find some sort of memory leak. I can try to recompile program with -g flag, however following executable will no longer be the same as the one that produced the core dump file.
When I try to do a backtrace, I get this
#0 0x0000003c992325e5 in ?? () from /lib64/libc.so.6
#1 0x0000003c99233dc5 in abort () from /lib64/libc.so.6
#2 0x00007f961117d3f2 in PrepareDumpAreas () from /opt/mqm/lib64/libmqe_r.so
#3 0x0000000000000000 in ?? ()
that tells me, that he is for some reason unable to read the executable I provided, but thats impossible because I'm sure the exe is correct. Might this be another result of the fact that it was not compiled for debugging?
My Question is: Is there another way to read dump core files? What can I do to make GDB work the way I need.
EDIT1: I also ran my own set of tests and watched, if the memory requirements for the process increased. On my enviroment, no leak was apparent. So it is specific for enviroment of my client (and, perhaps, specific to message loads that my program has to carry out)

How to force a program compiled with '-pg' dump its stat info when it is still running?

I'm developing in C++(g++) with a non-opensource lib.
every time I run the program, the lib will crash (it double-free some memory).
it's ok for my program now. but it's bad for profiling. I use -pg to profiling the program. As a result of the crash, no 'gmon.out' is generated. so I cannot profile it at all.
Question:
How to profiling a 'crashy' program (with gprof).
PS. valgrind is ok to analysis a crashy program.
regards!
There's a function you can call from your program to dump profile data (the same one that's automatically installed as an atexit handler when you link with -pg), but I don't know what it's called offhand.
The easyist thing to do it, just insert an exit(0); call at a suitable point in your program. Alternatively, you can set a breakpoint and use call exit(0) in GDB (except that debugging the program will affect the profile data if you stop it in the middle).

fatal error disappeared when running with gdb

I have a program which produces a fatal error with a testcase, and I can locate the problem by reading the log and the stack trace of the fatal - it turns out that there is a read operation upon a null pointer.
But when I try to attach gdb to it and set a breakpoint around the suspicious code, the null pointer just cannot be observed! The program works smoothly without any error.
This is a single-process, single-thread program, I didn't experience this kind of thing before. Can anyone give me some comments? Thanks.
Appended: I also tried to call pause() syscall before the fatal-trigger code, and expected to make the program sleep before fatal point and then attach the gdb on it on-the-fly, sadly, no fatal occurred.
It's only guesswork without looking at the code, but debuggers sometimes do this:
They initialize certain stuff for you
The timing of the operations is changed
I don't have a quote on GDB, but I do have one on valgrind (granted the two do wildly different things..)
My program crashes normally, but doesn't under Valgrind, or vice versa. What's happening?
When a program runs under Valgrind,
its environment is slightly different
to when it runs natively. For example,
the memory layout is different, and
the way that threads are scheduled is
different.
Same would go for GDB.
Most of the time this doesn't make any
difference, but it can, particularly
if your program is buggy.
So the true problem is likely in your program.
There can be several things happening.. The timing of the application can be changed, so if it's a multi threaded application it is possible that you for example first set the ready flag and then copy the data into the buffer, without debugger attached the other thread might access the buffer before the buffer is filled or some pointer is set.
It's could also be possible that some application has anti-debug functionality. Maybe the piece of code is never touched when running inside a debugger.
One way to analyze it is with a core dump. Which you can create by ulimit -c unlimited then start the application and when the core is dumped you could load it into gdb with gdb ./application ./core You can find a useful write-up here: http://www.ffnn.nl/pages/articles/linux/gdb-gnu-debugger-intro.php
If it is an invalid read on a pointer, then unpredictable behaviour is possible. Since you already know what is causing the fault, you should get rid of it asap. In general, expect the unexpected when dealing with faulty pointer operations.

Resources