Can't find my segmentation fault in my malloc shared library - c

I recoded malloc free and realloc in c using mmap and munmap. I compiled them as a shared library .so file.
Here is a simple test:
#include <stdlib.h>
int main() {
int i;
char *addr;
i = 0;
while (i < 1024)
{
addr = (char*)malloc(1024);
addr[0] = 42;
i++;
}
return (0);
}
Here is a run.sh that must replace the stdlib by my shared library:
#/bin/sh
export DYLD_LIBRARY_PATH=.
export DYLD_INSERT_LIBRARIES="libft_malloc.so"
export DYLD_FORCE_FLAT_NAMESPACE=1
$#
The problem is that when i am compiling directly the test file with my shared library and replacing the header in it, it is working well:
-> gcc test1.c libft_malloc.so
-> ./a.out
-> no error
But when i am running it with the run.sh that should just replace the official malloc library by my libft_malloc.so file, i am getting a segfault:
-> gcc test1.c
-> ./run.sh ./a.out
-> ./run.sh: line 5: 73502 Segmentation fault: 11 $#
I know the error is in my code and not in the run.sh or in the test.c because they are the officials files i must use to test my library in my school and those files are working well on other malloc repositories, but i can't find what can be the problem.
Here is my repository: https://github.com/Shirakawa42/malloc.git
I tried debugged by placing write() everywhere but the segfault don't seems to be in the malloc, so i'm lost.
edit:
It also segfault if we run a test without any malloc, but just by loading my library:
#include <stdlib.h>
int main() {
int i;
i = 0;
while (i < 1024)
{
i++;
}
return (0);
}
-> gcc test1.c
-> ./run.sh ./a.out
-> ./run.sh: line 5: 74764 Segmentation fault: 11 $#
edit 2:
Compiling with flag fsanitize=address repair the segfault, but it's absolutely not optimal
edit 3:
Setting the 2 first export manually in shell tell me:
dyld: warning: could not load inserted library 'libft_malloc.so' into library validated process because no suitable image found. Did find:
libft_malloc.so: code signing blocked mmap() of 'libft_malloc.so'
and after setting the third export all my actions make me segfault, like ls and vim, cd made me abort

dyld: warning: could not load inserted library 'libft_malloc.so' into library validated process because no suitable image found. Did find:
libft_malloc.so: code signing blocked mmap() of 'libft_malloc.so'
This error append when there are a segfault in your malloc or free, repairing free made it work.

You can debug it in gdb. First build your code with debug options:
gcc -g -O0
Above options should be used for both your lib and test program. Then you can try running you program in gdb:
gdb a.out
(gdb) r <arguments to a.out>
(gdb) bt <-- when it crashes
Linux loads you program in the memory and calls the entry point main. Startup code that compiler adds for the platform may have calls to malloc. Hence, the crash without malloc in your test code.

Related

Why shared library is unloaded while another program still uses it?

For what I understand, if there are more than one program using a shared library, the shared library won't get unloaded untill all program finishes.
I am reading The Linux Programming Interface:
42.4 Initialization and Finalization Functions It is possible to define one or more functions that are executed automatically when a
shared library is loaded and unloaded. This allows us to perform
initialization and finalization actions when working with shared
libraries. Initialization and finalization functions are executed
regardless of whether the library is loaded automatically or loaded
explicitly using the dlopen interface (Section 42.1).
Initialization and finalization functions are defined using the gcc
constructor and destructor attributes. Each function that is to be
executed when the library is loaded should be defined as follows:
void __attribute__ ((constructor)) some_name_load(void)
{
/* Initialization code */
}
Unload functions are similarly defined:
void __attribute__ ((destructor)) some_name_unload(void)
{
/* Finalization code */
} The function names `some_name_load()` and `some_name_unload()` can be replaced by any desired names. ....
Then I wrote 3 files to test:
foo.c
#include <stdio.h>
void __attribute__((constructor)) call_me_when_load(void){
printf("Loading....\n");
}
void __attribute__((destructor)) call_me_when_unload(void){
printf("Unloading...\n");
}
int xyz(int a ){
return a + 3;
}
main.c
#include <stdio.h>
#include <unistd.h>
int main(){
int xyz(int);
int b;
for(int i = 0;i < 1; i++){
b = xyz(i);
printf("xyz(i) is: %d\n", b);
}
}
main_while_sleep.c
#include <stdio.h>
#include <unistd.h>
int main(){
int xyz(int);
int b;
for(int i = 0;i < 10; i++){
b = xyz(i);
sleep(1);
printf("xyz(i) is: %d\n", b);
}
}
Then I compile a shared library and 2 executables:
gcc -g -Wall -fPIC -shared -o libdemo.so foo.c
gcc -g -Wall -o main main.c libdemo.so
gcc -g -Wall -o main_while_sleep main_while_sleep.c libdemo.so
finally run LD_LIBRARY_PATH=. ./main_while_sleep in a shell and run LD_LIBRARY_PATH=. ./main in another:
main_while_sleep output:
Loading....
xyz(i) is: 3
xyz(i) is: 4
xyz(i) is: 5
xyz(i) is: 6
xyz(i) is: 7
xyz(i) is: 8
xyz(i) is: 9
xyz(i) is: 10
xyz(i) is: 11
xyz(i) is: 12
Unloading...
main output:
Loading....
xyz(i) is: 3
Unloading...
My question is, while main_while_sleep is not finished, why Unloading is printed in main, which indicates the shared library has been unloaded? The shared library shouldn't be unloaded yet, main_while_sleep is still running!
Do I get something wrong?
My question is, while main_while_sleep is not finished, why Unloading is printed in main, which indicates the shared library has been unloaded? The shared library shouldn't be unloaded yet, main_while_sleep is still running!
You are confusing/conflating initialization/deinitialization with load/unload.
A constructor is an initialization function that is called after a shared library has been mapped into a given process's memory.
It does not affect any other process (which is in a separate, per-process address space).
Likewise, the mapping (or unmapping) of a shared library in a given process does not affect any other process.
When a process maps a library, nothing is "loaded". When the process tries to access a memory page that is part of the shared library, it receives a page fault and the given page is mapped, the page is marked resident, and the faulting instruction is restarted.
There is much more detail in my answers:
How does mmap improve file reading speed?
Which segments are affected by a copy-on-write?
read line by line in the most efficient way *platform specific*
Is Dynamic Linker part of Kernel or GCC Library on Linux Systems?
Malloc is using 10x the amount of memory necessary

How can I print call trace in a C program [duplicate]

Is there any way to dump the call stack in a running process in C or C++ every time a certain function is called? What I have in mind is something like this:
void foo()
{
print_stack_trace();
// foo's body
return
}
Where print_stack_trace works similarly to caller in Perl.
Or something like this:
int main (void)
{
// will print out debug info every time foo() is called
register_stack_trace_function(foo);
// etc...
}
where register_stack_trace_function puts some sort of internal breakpoint that will cause a stack trace to be printed whenever foo is called.
Does anything like this exist in some standard C library?
I am working on Linux, using GCC.
Background
I have a test run that behaves differently based on some commandline switches that shouldn't affect this behavior. My code has a pseudo-random number generator that I assume is being called differently based on these switches. I want to be able to run the test with each set of switches and see if the random number generator is called differently for each one.
Survey of C/C++ backtrace methods
In this answer I will try to run a single benchmark for a bunch of solutions to see which one runs faster, while also considering other points such as features and portability.
Tool
Time / call
Line number
Function name
C++ demangling
Recompile
Signal safe
As string
C
C++23 <stacktrace> GCC 12.1
7 us
y
y
y
y
n
y
n
Boost 1.74 stacktrace()
5 us
y
y
y
y
n
y
n
Boost 1.74 stacktrace::safe_dump_to
y
n
n
glibc backtrace_symbols_fd
25 us
n
-rdynamic
hacks
y
y
n
y
glibc backtrace_symbols
21 us
n
-rdynamic
hacks
y
n
y
y
GDB scripting
600 us
y
y
y
n
y
n
y
GDB code injection
n
n
y
libunwind
y
libdwfl
4 ms
n
y
libbacktrace
y
Empty cells mean "TODO", not "no".
us: microsecond
Line number: shows actual line number, not just function name + a memory address.
It is usually possible to recover the line number from an address manually after the fact with addr2line. But it is a pain.
Recompile: requires recompiling the program to get your traces. Not recompiling is better!
Signal safe: crucial for the important uses case of "getting a stack trace in case of segfault": How to automatically generate a stacktrace when my program crashes
As string: you get the stack trace as a string in the program itself, as opposed to e.g. just printing to stdout. Usually implies not signal safe, as we don't know the size of the stack trace string size in advance, and therefore requires malloc which is not async signal safe.
C: does it work on a plain-C project (yes, there are still poor souls out there), or is C++ required?
Test setup
All benchmarks will run the following
main.cpp
#include <cstdlib> // strtoul
#include <mystacktrace.h>
void my_func_2(void) {
print_stacktrace(); // line 6
}
void my_func_1(double f) {
(void)f;
my_func_2();
}
void my_func_1(int i) {
(void)i;
my_func_2(); // line 16
}
int main(int argc, char **argv) {
long long unsigned int n;
if (argc > 1) {
n = std::strtoul(argv[1], NULL, 0);
} else {
n = 1;
}
for (long long unsigned int i = 0; i < n; ++i) {
my_func_1(1); // line 27
}
}
This input is designed to test C++ name demangling since my_func_1(int) and my_func_1(float) are necessarily mangled as a way to implement C++ function overload.
We differentiate between the benchmarks by using different -I includes to point to different implementations of print_stacktrace().
Each benchmark is done with a command of form:
time ./stacktrace.out 100000 &>/dev/null
The number of iterations is adjusted for each implementation to produce a total runtime of the order of 1s for that benchmark.
-O0 is used on all tests below unless noted. Stack traces may be irreparably mutilated by certain optimizations. Tail call optimization is a notable example of that: What is tail call optimization? There's nothing we can do about it.
C++23 <stacktrace>
This method was previously mentioned at: https://stackoverflow.com/a/69384663/895245 please consider upvoting that answer.
This is the best solution... it's portable, fast, shows line numbers and demangles C++ symbols. This option will displace every other alternative as soon as it becomes more widely available, with the exception perhaps only of GDB for one-offs without the need or recompilation.
cpp20_stacktrace/mystacktrace.h
#include <iostream>
#include <stacktrace>
void print_stacktrace() {
std::cout << std::stacktrace::current();
}
GCC 12.1.0 from Ubuntu 22.04 does not have support compiled in, so for now I built it from source as per: How to edit and re-build the GCC libstdc++ C++ standard library source? and set --enable-libstdcxx-backtrace=yes, and it worked!
Compile with:
g++ -O0 -ggdb3 -Wall -Wextra -pedantic -std=c++23 -o cpp20_stacktrace.out main.cpp -lstdc++_libbacktrace
Sample output:
0# print_stacktrace() at cpp20_stacktrace/mystacktrace.h:5
1# my_func_2() at /home/ciro/main.cpp:6
2# my_func_1(int) at /home/ciro/main.cpp:16
3# at /home/ciro/main.cpp:27
4# at :0
5# at :0
6# at :0
7#
If we try to use GCC 12.1.0 from Ubuntu 22.04:
sudo apt install g++-12
g++-12 -ggdb3 -O2 -std=c++23 -Wall -Wextra -pedantic -o stacktrace.out stacktrace.cpp -lstdc++_libbacktrace
It fails with:
stacktrace.cpp: In function ‘void my_func_2()’:
stacktrace.cpp:6:23: error: ‘std::stacktrace’ has not been declared
6 | std::cout << std::stacktrace::current();
| ^~~~~~~~~~
Checking build options with:
g++-12 -v
does not show:
--enable-libstdcxx-backtrace=yes
so it wasn't compiled in. Bibliography:
How to use <stacktrace> in GCC trunk?
How can I generate a C++23 stacktrace with GCC 12.1?
It does not fail on the include because the header file:
/usr/include/c++/12
has a feature check:
#if __cplusplus > 202002L && _GLIBCXX_HAVE_STACKTRACE
Boost stacktrace
The library has changed quite a lot around Ubuntu 22.04, so make sure your version matches: Boost stack-trace not showing function names and line numbers
The library is pretty much superseded by the more portable C++23 implementation, but remains a very good option for those that are not at that standard version yet, but already have a "Boost clearance".
Documented at: https://www.boost.org/doc/libs/1_66_0/doc/html/stacktrace/getting_started.html#stacktrace.getting_started.how_to_print_current_call_stack
Tested on Ubuntu 22.04, boost 1.74.0, you should do:
boost_stacktrace/mystacktrace.h
#include <iostream>
#define BOOST_STACKTRACE_LINK
#include <boost/stacktrace.hpp>
void print_stacktrace(void) {
std::cout << boost::stacktrace::stacktrace();
}
On Ubuntu 19.10 boost 1.67.0 to get the line numbers we had to instead:
#include <iostream>
#define BOOST_STACKTRACE_USE_ADDR2LINE
#include <boost/stacktrace.hpp>
void print_stacktrace(void) {
std::cout << boost::stacktrace::stacktrace();
}
which would call out to the addr2line executable and be 1000x slower than the newer Boost version.
The package libboost-stacktrace-dev did not exist at all on Ubuntu 16.04.
The rest of this section considers only the Ubuntu 22.04, boost 1.74 behaviour.
Compile:
sudo apt-get install libboost-stacktrace-dev
g++ -O0 -ggdb3 -Wall -Wextra -pedantic -std=c++11 -o boost_stacktrace.out main.cpp -lboost_stacktrace_backtrace
Sample output:
0# print_stacktrace() at boost_stacktrace/mystacktrace.h:7
1# my_func_2() at /home/ciro/main.cpp:7
2# my_func_1(int) at /home/ciro/main.cpp:17
3# main at /home/ciro/main.cpp:26
4# __libc_start_call_main at ../sysdeps/nptl/libc_start_call_main.h:58
5# __libc_start_main at ../csu/libc-start.c:379
6# _start in ./boost_stacktrace.out
Note that the lines are off by one line. It was suggested in the comments that this is because the following instruction address is being considered.
Boost stacktrace header only
What the BOOST_STACKTRACE_LINK does is to require -lboost_stacktrace_backtrace at link time, so we imagine without that it will just work. This would be a good option for devs who don't have the "Boost clearance" to just add as one offs to debug.
TODO unfortunately it didn't so well for me:
#include <iostream>
#include <boost/stacktrace.hpp>
void print_stacktrace(void) {
std::cout << boost::stacktrace::stacktrace();
}
then:
g++ -O0 -ggdb3 -Wall -Wextra -pedantic -std=c++11 -o boost_stacktrace_header_only.out main.cpp
contains the overly short output:
0# 0x000055FF74AFB601 in ./boost_stacktrace_header_only.out
1# 0x000055FF74AFB66C in ./boost_stacktrace_header_only.out
2# 0x000055FF74AFB69C in ./boost_stacktrace_header_only.out
3# 0x000055FF74AFB6F7 in ./boost_stacktrace_header_only.out
4# 0x00007F0176E7BD90 in /lib/x86_64-linux-gnu/libc.so.6
5# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
6# 0x000055FF74AFB4E5 in ./boost_stacktrace_header_only.out
which we can't even use with addr2line. Maybe we have to pass some other define from: https://www.boost.org/doc/libs/1_80_0/doc/html/stacktrace/configuration_and_build.html ?
Tested on Ubuntu 22.04. boost 1.74.
Boost boost::stacktrace::safe_dump_to
This is an interesting alternative to boost::stacktrace::stacktrace as it writes the stack trace in a async signal safe manner to a file, which makes it a good option for automatically dumping stack traces on segfaults which is a super common use case: How to automatically generate a stacktrace when my program crashes
Documented at: https://www.boost.org/doc/libs/1_70_0/doc/html/boost/stacktrace/safe_dump_1_3_38_7_6_2_1_6.html
TODO get it to work. All I see each time is a bunch of random bytes. My attempt:
boost_stacktrace_safe/mystacktrace.h
#include <unistd.h>
#define BOOST_STACKTRACE_LINK
#include <boost/stacktrace.hpp>
void print_stacktrace(void) {
boost::stacktrace::safe_dump_to(0, 1024, STDOUT_FILENO);
}
Sample output:
1[FU1[FU"2[FU}2[FUm1#n10[FU
Changes drastically each time, suggesting it is random memory addresses.
Tested on Ubuntu 22.04, boost 1.74.0.
glibc backtrace
This method is quite portable as it comes with glibc itself. Documented at: https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
Tested on Ubuntu 22.04, glibc 2.35.
glibc_backtrace_symbols_fd/mystacktrace.h
#include <execinfo.h> /* backtrace, backtrace_symbols_fd */
#include <unistd.h> /* STDOUT_FILENO */
void print_stacktrace(void) {
size_t size;
enum Constexpr { MAX_SIZE = 1024 };
void *array[MAX_SIZE];
size = backtrace(array, MAX_SIZE);
backtrace_symbols_fd(array, size, STDOUT_FILENO);
}
Compile with:
g++ -O0 -ggdb3 -Wall -Wextra -pedantic -rdynamic -std=c++11 -o glibc_backtrace_symbols_fd.out main.cpp
Sample output with -rdynamic:
./glibc_backtrace_symbols.out(_Z16print_stacktracev+0x47) [0x556e6a131230]
./glibc_backtrace_symbols.out(_Z9my_func_2v+0xd) [0x556e6a1312d6]
./glibc_backtrace_symbols.out(_Z9my_func_1i+0x14) [0x556e6a131306]
./glibc_backtrace_symbols.out(main+0x58) [0x556e6a131361]
/lib/x86_64-linux-gnu/libc.so.6(+0x29d90) [0x7f175e7bdd90]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80) [0x7f175e7bde40]
./glibc_backtrace_symbols.out(_start+0x25) [0x556e6a131125]
Sample output without -rdynamic:
./glibc_backtrace_symbols_fd_no_rdynamic.out(+0x11f0)[0x556bd40461f0]
./glibc_backtrace_symbols_fd_no_rdynamic.out(+0x123c)[0x556bd404623c]
./glibc_backtrace_symbols_fd_no_rdynamic.out(+0x126c)[0x556bd404626c]
./glibc_backtrace_symbols_fd_no_rdynamic.out(+0x12c7)[0x556bd40462c7]
/lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x7f0da2b70d90]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0x80)[0x7f0da2b70e40]
./glibc_backtrace_symbols_fd_no_rdynamic.out(+0x10e5)[0x556bd40460e5]
To get the line numbers without -rdynamic we can use addr2line:
addr2line -C -e glibc_backtrace_symbols_fd_no_rdynamic.out 0x11f0 0x123c 0x126c 0x12c7
addr2line cannot unfortunately handle the function name + offset in function format of when we are not using -rdynamic, e.g. _Z9my_func_2v+0xd.
GDB can however:
gdb -nh -batch -ex 'info line *(_Z9my_func_2v+0xd)' -ex 'info line *(_Z9my_func_1i+0x14)' glibc_backtrace_symbols.out
Line 7 of "main.cpp" starts at address 0x12d6 <_Z9my_func_2v+13> and ends at 0x12d9 <_Z9my_func_1d>.
Line 17 of "main.cpp" starts at address 0x1306 <_Z9my_func_1i+20> and ends at 0x1309 <main(int, char**)>.
A helper to make it more bearable:
addr2lines() (
perl -ne '$m = s/(.*).*\(([^)]*)\).*/gdb -nh -q -batch -ex "info line *\2" \1/;print $_ if $m' | bash
)
Usage:
xsel -b | addr2lines
glibc backtrace_symbols
A version of backtrace_symbols_fd that returns a string rather than printing to a file handle.
glibc_backtrace_symbols/mystacktrace.h
#include <execinfo.h> /* backtrace, backtrace_symbols */
#include <stdio.h> /* printf */
void print_stacktrace(void) {
char **strings;
size_t i, size;
enum Constexpr { MAX_SIZE = 1024 };
void *array[MAX_SIZE];
size = backtrace(array, MAX_SIZE);
strings = backtrace_symbols(array, size);
for (i = 0; i < size; i++)
printf("%s\n", strings[i]);
free(strings);
}
glibc backtrace with C++ demangling hack 1: -export-dynamic + dladdr
I couldn't find a simple way to automatically demangle C++ symbols with glibc backtrace.
https://panthema.net/2008/0901-stacktrace-demangled/
https://gist.github.com/fmela/591333/c64f4eb86037bb237862a8283df70cdfc25f01d3
Adapted from: https://gist.github.com/fmela/591333/c64f4eb86037bb237862a8283df70cdfc25f01d3
This is a "hack" because it requires changing the ELF with -export-dynamic.
glibc_ldl.cpp
#include <dlfcn.h> // for dladdr
#include <cxxabi.h> // for __cxa_demangle
#include <cstdio>
#include <string>
#include <sstream>
#include <iostream>
// This function produces a stack backtrace with demangled function & method names.
std::string backtrace(int skip = 1)
{
void *callstack[128];
const int nMaxFrames = sizeof(callstack) / sizeof(callstack[0]);
char buf[1024];
int nFrames = backtrace(callstack, nMaxFrames);
char **symbols = backtrace_symbols(callstack, nFrames);
std::ostringstream trace_buf;
for (int i = skip; i < nFrames; i++) {
Dl_info info;
if (dladdr(callstack[i], &info)) {
char *demangled = NULL;
int status;
demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
std::snprintf(
buf,
sizeof(buf),
"%-3d %*p %s + %zd\n",
i,
(int)(2 + sizeof(void*) * 2),
callstack[i],
status == 0 ? demangled : info.dli_sname,
(char *)callstack[i] - (char *)info.dli_saddr
);
free(demangled);
} else {
std::snprintf(buf, sizeof(buf), "%-3d %*p\n",
i, (int)(2 + sizeof(void*) * 2), callstack[i]);
}
trace_buf << buf;
std::snprintf(buf, sizeof(buf), "%s\n", symbols[i]);
trace_buf << buf;
}
free(symbols);
if (nFrames == nMaxFrames)
trace_buf << "[truncated]\n";
return trace_buf.str();
}
void my_func_2(void) {
std::cout << backtrace() << std::endl;
}
void my_func_1(double f) {
(void)f;
my_func_2();
}
void my_func_1(int i) {
(void)i;
my_func_2();
}
int main() {
my_func_1(1);
my_func_1(2.0);
}
Compile and run:
g++ -fno-pie -ggdb3 -O0 -no-pie -o glibc_ldl.out -std=c++11 -Wall -Wextra \
-pedantic-errors -fpic glibc_ldl.cpp -export-dynamic -ldl
./glibc_ldl.out
output:
1 0x40130a my_func_2() + 41
./glibc_ldl.out(_Z9my_func_2v+0x29) [0x40130a]
2 0x40139e my_func_1(int) + 16
./glibc_ldl.out(_Z9my_func_1i+0x10) [0x40139e]
3 0x4013b3 main + 18
./glibc_ldl.out(main+0x12) [0x4013b3]
4 0x7f7594552b97 __libc_start_main + 231
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7f7594552b97]
5 0x400f3a _start + 42
./glibc_ldl.out(_start+0x2a) [0x400f3a]
1 0x40130a my_func_2() + 41
./glibc_ldl.out(_Z9my_func_2v+0x29) [0x40130a]
2 0x40138b my_func_1(double) + 18
./glibc_ldl.out(_Z9my_func_1d+0x12) [0x40138b]
3 0x4013c8 main + 39
./glibc_ldl.out(main+0x27) [0x4013c8]
4 0x7f7594552b97 __libc_start_main + 231
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7f7594552b97]
5 0x400f3a _start + 42
./glibc_ldl.out(_start+0x2a) [0x400f3a]
Tested on Ubuntu 18.04.
glibc backtrace with C++ demangling hack 2: parse backtrace output
Shown at: https://panthema.net/2008/0901-stacktrace-demangled/
This is a hack because it requires parsing.
TODO get it to compile and show it here.
GDB scripting
We can also do this with GDB without recompiling by using: How to do an specific action when a certain breakpoint is hit in GDB?
We setup an empty backtrace function for our testing:
gdb/mystacktrace.h
void print_stacktrace(void) {}
and then with:
main.gdb
start
break print_stacktrace
commands
silent
backtrace
printf "\n"
continue
end
continue
we can run:
gdb -nh -batch -x main.gdb --args gdb.out
Sample output:
Temporary breakpoint 1 at 0x11a7: file main.cpp, line 21.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffc3e8) at main.cpp:21
warning: Source file is more recent than executable.
21 if (argc > 1) {
Breakpoint 2 at 0x555555555151: file gdb/mystacktrace.h, line 1.
#0 print_stacktrace () at gdb/mystacktrace.h:1
#1 0x0000555555555161 in my_func_2 () at main.cpp:6
#2 0x0000555555555191 in my_func_1 (i=1) at main.cpp:16
#3 0x00005555555551ec in main (argc=1, argv=0x7fffffffc3e8) at main.cpp:27
[Inferior 1 (process 165453) exited normally]
The above can be made more usable with the following Bash function:
gdbbt() (
tmpfile=$(mktemp /tmp/gdbbt.XXXXXX)
fn="$1"
shift
printf '%s' "
start
break $fn
commands
silent
backtrace
printf \"\n\"
continue
end
continue
" > "$tmpfile"
gdb -nh -batch -x "$tmpfile" -args "$#"
rm -f "$tmpfile"
)
Usage:
gdbbt print_stacktrace gdb.out 2
I don't know how to make commands with -ex without the temporary file: Problems adding a breakpoint with commands from command line with ex command
Tested in Ubuntu 22.04, GDB 12.0.90.
GDB code injection
TODO this is the dream! It might allow for both compiled-liked speeds, but without the need to recompile! Either:
with compile code + one of the other options, ideally C++23 <stacktrace>: How to call assembly in gdb? Might already be possible. But compile code is mega-quirky so I'm lazy to even try
a built-in dbt command analogous to dprintf dynamic printf: How to do an specific action when a certain breakpoint is hit in GDB?
libunwind
TODO does this have any advantage over glibc backtrace? Very similar output, also requires modifying the build command, but not part of glibc so requires an extra package installation.
Code adapted from: https://eli.thegreenplace.net/2015/programmatic-access-to-the-call-stack-in-c/
main.c
/* This must be on top. */
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
/* Paste this on the file you want to debug. */
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <stdio.h>
void print_trace() {
char sym[256];
unw_context_t context;
unw_cursor_t cursor;
unw_getcontext(&context);
unw_init_local(&cursor, &context);
while (unw_step(&cursor) > 0) {
unw_word_t offset, pc;
unw_get_reg(&cursor, UNW_REG_IP, &pc);
if (pc == 0) {
break;
}
printf("0x%lx:", pc);
if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) {
printf(" (%s+0x%lx)\n", sym, offset);
} else {
printf(" -- error: unable to obtain symbol name for this frame\n");
}
}
puts("");
}
void my_func_3(void) {
print_trace();
}
void my_func_2(void) {
my_func_3();
}
void my_func_1(void) {
my_func_3();
}
int main(void) {
my_func_1(); /* line 46 */
my_func_2(); /* line 47 */
return 0;
}
Compile and run:
sudo apt-get install libunwind-dev
gcc -fno-pie -ggdb3 -O3 -no-pie -o main.out -std=c99 \
-Wall -Wextra -pedantic-errors main.c -lunwind
Either #define _XOPEN_SOURCE 700 must be on top, or we must use -std=gnu99:
Is the type `stack_t` no longer defined on linux?
Glibc - error in ucontext.h, but only with -std=c11
Run:
./main.out
Output:
0x4007db: (main+0xb)
0x7f4ff50aa830: (__libc_start_main+0xf0)
0x400819: (_start+0x29)
0x4007e2: (main+0x12)
0x7f4ff50aa830: (__libc_start_main+0xf0)
0x400819: (_start+0x29)
and:
addr2line -e main.out 0x4007db 0x4007e2
gives:
/home/ciro/main.c:34
/home/ciro/main.c:49
With -O0:
0x4009cf: (my_func_3+0xe)
0x4009e7: (my_func_1+0x9)
0x4009f3: (main+0x9)
0x7f7b84ad7830: (__libc_start_main+0xf0)
0x4007d9: (_start+0x29)
0x4009cf: (my_func_3+0xe)
0x4009db: (my_func_2+0x9)
0x4009f8: (main+0xe)
0x7f7b84ad7830: (__libc_start_main+0xf0)
0x4007d9: (_start+0x29)
and:
addr2line -e main.out 0x4009f3 0x4009f8
gives:
/home/ciro/main.c:47
/home/ciro/main.c:48
Tested on Ubuntu 16.04, GCC 6.4.0, libunwind 1.1.
libunwind with C++ name demangling
Code adapted from: https://eli.thegreenplace.net/2015/programmatic-access-to-the-call-stack-in-c/
unwind.cpp
#define UNW_LOCAL_ONLY
#include <cxxabi.h>
#include <libunwind.h>
#include <cstdio>
#include <cstdlib>
#include <iostream>
void backtrace() {
unw_cursor_t cursor;
unw_context_t context;
// Initialize cursor to current frame for local unwinding.
unw_getcontext(&context);
unw_init_local(&cursor, &context);
// Unwind frames one by one, going up the frame stack.
while (unw_step(&cursor) > 0) {
unw_word_t offset, pc;
unw_get_reg(&cursor, UNW_REG_IP, &pc);
if (pc == 0) {
break;
}
std::printf("0x%lx:", pc);
char sym[256];
if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) {
char* nameptr = sym;
int status;
char* demangled = abi::__cxa_demangle(sym, nullptr, nullptr, &status);
if (status == 0) {
nameptr = demangled;
}
std::printf(" (%s+0x%lx)\n", nameptr, offset);
std::free(demangled);
} else {
std::printf(" -- error: unable to obtain symbol name for this frame\n");
}
}
}
void my_func_2(void) {
backtrace();
std::cout << std::endl; // line 43
}
void my_func_1(double f) {
(void)f;
my_func_2();
}
void my_func_1(int i) {
(void)i;
my_func_2();
} // line 54
int main() {
my_func_1(1);
my_func_1(2.0);
}
Compile and run:
sudo apt-get install libunwind-dev
g++ -fno-pie -ggdb3 -O0 -no-pie -o unwind.out -std=c++11 \
-Wall -Wextra -pedantic-errors unwind.cpp -lunwind -pthread
./unwind.out
Output:
0x400c80: (my_func_2()+0x9)
0x400cb7: (my_func_1(int)+0x10)
0x400ccc: (main+0x12)
0x7f4c68926b97: (__libc_start_main+0xe7)
0x400a3a: (_start+0x2a)
0x400c80: (my_func_2()+0x9)
0x400ca4: (my_func_1(double)+0x12)
0x400ce1: (main+0x27)
0x7f4c68926b97: (__libc_start_main+0xe7)
0x400a3a: (_start+0x2a)
and then we can find the lines of my_func_2 and my_func_1(int) with:
addr2line -e unwind.out 0x400c80 0x400cb7
which gives:
/home/ciro/test/unwind.cpp:43
/home/ciro/test/unwind.cpp:54
TODO: why are the lines off by one?
Tested on Ubuntu 18.04, GCC 7.4.0, libunwind 1.2.1.
Linux kernel
How to print the current thread stack trace inside the Linux kernel?
libdwfl
This was originally mentioned at: https://stackoverflow.com/a/60713161/895245 and it might be the best method, but I have to benchmark a bit more, but please go upvote that answer.
TODO: I tried to minimize the code in that answer, which was working, to a single function, but it is segfaulting, let me know if anyone can find why.
dwfl.cpp: answer reached 30k chars and this was the easiest cut: https://gist.github.com/cirosantilli/f1dd3ee5d324b9d24e40f855723544ac
Compile and run:
sudo apt install libdw-dev libunwind-dev
g++ -fno-pie -ggdb3 -O0 -no-pie -o dwfl.out -std=c++11 -Wall -Wextra -pedantic-errors dwfl.cpp -ldw -lunwind
./dwfl.out
We also need libunwind as that makes results more correct. If you do without it, it runs, but you will see that some of the lines are a bit wrong.
Output:
0: 0x402b72 stacktrace[abi:cxx11]() at /home/ciro/test/dwfl.cpp:65
1: 0x402cda my_func_2() at /home/ciro/test/dwfl.cpp:100
2: 0x402d76 my_func_1(int) at /home/ciro/test/dwfl.cpp:111
3: 0x402dd1 main at /home/ciro/test/dwfl.cpp:122
4: 0x7ff227ea0d8f __libc_start_call_main at ../sysdeps/nptl/libc_start_call_main.h:58
5: 0x7ff227ea0e3f __libc_start_main##GLIBC_2.34 at ../csu/libc-start.c:392
6: 0x402534 _start at ../csu/libc-start.c:-1
0: 0x402b72 stacktrace[abi:cxx11]() at /home/ciro/test/dwfl.cpp:65
1: 0x402cda my_func_2() at /home/ciro/test/dwfl.cpp:100
2: 0x402d5f my_func_1(double) at /home/ciro/test/dwfl.cpp:106
3: 0x402de2 main at /home/ciro/test/dwfl.cpp:123
4: 0x7ff227ea0d8f __libc_start_call_main at ../sysdeps/nptl/libc_start_call_main.h:58
5: 0x7ff227ea0e3f __libc_start_main##GLIBC_2.34 at ../csu/libc-start.c:392
6: 0x402534 _start at ../csu/libc-start.c:-1
Benchmark run:
g++ -fno-pie -ggdb3 -O3 -no-pie -o dwfl.out -std=c++11 -Wall -Wextra -pedantic-errors dwfl.cpp -ldw
time ./dwfl.out 1000 >/dev/null
Output:
real 0m3.751s
user 0m2.822s
sys 0m0.928s
So we see that this method is 10x faster than Boost's stacktrace, and might therefore be applicable to more use cases.
Tested in Ubuntu 22.04 amd64, libdw-dev 0.186, libunwind 1.3.2.
libbacktrace
https://github.com/ianlancetaylor/libbacktrace
Considering the harcore library author, it is worth trying this out, maybe it is The One. TODO check it out.
A C library that may be linked into a C/C++ program to produce symbolic backtraces
As of October 2020, libbacktrace supports ELF, PE/COFF, Mach-O, and XCOFF executables with DWARF debugging information. In other words, it supports GNU/Linux, *BSD, macOS, Windows, and AIX. The library is written to make it straightforward to add support for other object file and debugging formats.
The library relies on the C++ unwind API defined at https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html This API is provided by GCC and clang.
See also
How can one grab a stack trace in C?
How to make backtrace()/backtrace_symbols() print the function names?
Is there a portable/standard-compliant way to get filenames and linenumbers in a stack trace?
Best way to invoke gdb from inside program to print its stacktrace?
automatic stack trace on failure:
on C++ exception: C++ display stack trace on exception
generic: How to automatically generate a stacktrace when my program crashes
For a linux-only solution you can use backtrace(3) that simply returns an array of void * (in fact each of these point to the return address from the corresponding stack frame). To translate these to something of use, there's backtrace_symbols(3).
Pay attention to the notes section in backtrace(3):
The symbol names may be unavailable
without the use of special linker
options.
For systems using the GNU linker, it is necessary to use the
-rdynamic linker
option. Note that names of "static" functions are not exposed,
and won't be
available in the backtrace.
In C++23, there will be <stacktrace>, and then you can do:
#include <stacktrace>
/* ... */
std::cout << std::stacktrace::current();
Further details:
  • https://en.cppreference.com/w/cpp/header/stacktrace
  • https://en.cppreference.com/w/cpp/utility/basic_stacktrace/operator_ltlt
Is there any way to dump the call stack in a running process in C or C++ every time a certain function is called?
You can use a macro function instead of return statement in the specific function.
For example, instead of using return,
int foo(...)
{
if (error happened)
return -1;
... do something ...
return 0
}
You can use a macro function.
#include "c-callstack.h"
int foo(...)
{
if (error happened)
NL_RETURN(-1);
... do something ...
NL_RETURN(0);
}
Whenever an error happens in a function, you will see Java-style call stack as shown below.
Error(code:-1) at : so_topless_ranking_server (sample.c:23)
Error(code:-1) at : nanolat_database (sample.c:31)
Error(code:-1) at : nanolat_message_queue (sample.c:39)
Error(code:-1) at : main (sample.c:47)
Full source code is available here.
c-callstack at https://github.com/Nanolat
Linux specific, TLDR:
backtrace in glibc produces accurate stacktraces only when -lunwind is linked (undocumented platform-specific feature).
To output function name, source file and line number use #include <elfutils/libdwfl.h> (this library is documented only in its header file). backtrace_symbols and backtrace_symbolsd_fd are least informative.
On modern Linux your can get the stacktrace addresses using function backtrace. The undocumented way to make backtrace produce more accurate addresses on popular platforms is to link with -lunwind (libunwind-dev on Ubuntu 18.04) (see the example output below). backtrace uses function _Unwind_Backtrace and by default the latter comes from libgcc_s.so.1 and that implementation is most portable. When -lunwind is linked it provides a more accurate version of _Unwind_Backtrace but this library is less portable (see supported architectures in libunwind/src).
Unfortunately, the companion backtrace_symbolsd and backtrace_symbols_fd functions have not been able to resolve the stacktrace addresses to function names with source file name and line number for probably a decade now (see the example output below).
However, there is another method to resolve addresses to symbols and it produces the most useful traces with function name, source file and line number. The method is to #include <elfutils/libdwfl.h>and link with -ldw (libdw-dev on Ubuntu 18.04).
Working C++ example (test.cc):
#include <stdexcept>
#include <iostream>
#include <cassert>
#include <cstdlib>
#include <string>
#include <boost/core/demangle.hpp>
#include <execinfo.h>
#include <elfutils/libdwfl.h>
struct DebugInfoSession {
Dwfl_Callbacks callbacks = {};
char* debuginfo_path = nullptr;
Dwfl* dwfl = nullptr;
DebugInfoSession() {
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);
}
~DebugInfoSession() {
dwfl_end(dwfl);
}
DebugInfoSession(DebugInfoSession const&) = delete;
DebugInfoSession& operator=(DebugInfoSession const&) = delete;
};
struct DebugInfo {
void* ip;
std::string function;
char const* file;
int line;
DebugInfo(DebugInfoSession const& dis, void* ip)
: ip(ip)
, file()
, line(-1)
{
// Get function name.
uintptr_t ip2 = reinterpret_cast<uintptr_t>(ip);
Dwfl_Module* module = dwfl_addrmodule(dis.dwfl, ip2);
char const* name = dwfl_module_addrname(module, ip2);
function = name ? boost::core::demangle(name) : "<unknown>";
// Get source filename and line number.
if(Dwfl_Line* dwfl_line = dwfl_module_getsrc(module, ip2)) {
Dwarf_Addr addr;
file = dwfl_lineinfo(dwfl_line, &addr, &line, nullptr, nullptr, nullptr);
}
}
};
std::ostream& operator<<(std::ostream& s, DebugInfo const& di) {
s << di.ip << ' ' << di.function;
if(di.file)
s << " at " << di.file << ':' << di.line;
return s;
}
void terminate_with_stacktrace() {
void* stack[512];
int stack_size = ::backtrace(stack, sizeof stack / sizeof *stack);
// Print the exception info, if any.
if(auto ex = std::current_exception()) {
try {
std::rethrow_exception(ex);
}
catch(std::exception& e) {
std::cerr << "Fatal exception " << boost::core::demangle(typeid(e).name()) << ": " << e.what() << ".\n";
}
catch(...) {
std::cerr << "Fatal unknown exception.\n";
}
}
DebugInfoSession dis;
std::cerr << "Stacktrace of " << stack_size << " frames:\n";
for(int i = 0; i < stack_size; ++i) {
std::cerr << i << ": " << DebugInfo(dis, stack[i]) << '\n';
}
std::cerr.flush();
std::_Exit(EXIT_FAILURE);
}
int main() {
std::set_terminate(terminate_with_stacktrace);
throw std::runtime_error("test exception");
}
Compiled on Ubuntu 18.04.4 LTS with gcc-8.3:
g++ -o test.o -c -m{arch,tune}=native -std=gnu++17 -W{all,extra,error} -g -Og -fstack-protector-all test.cc
g++ -o test -g test.o -ldw -lunwind
Outputs:
Fatal exception std::runtime_error: test exception.
Stacktrace of 7 frames:
0: 0x55f3837c1a8c terminate_with_stacktrace() at /home/max/src/test/test.cc:76
1: 0x7fbc1c845ae5 <unknown>
2: 0x7fbc1c845b20 std::terminate()
3: 0x7fbc1c845d53 __cxa_throw
4: 0x55f3837c1a43 main at /home/max/src/test/test.cc:103
5: 0x7fbc1c3e3b96 __libc_start_main at ../csu/libc-start.c:310
6: 0x55f3837c17e9 _start
When no -lunwind is linked, it produces a less accurate stacktrace:
0: 0x5591dd9d1a4d terminate_with_stacktrace() at /home/max/src/test/test.cc:76
1: 0x7f3c18ad6ae6 <unknown>
2: 0x7f3c18ad6b21 <unknown>
3: 0x7f3c18ad6d54 <unknown>
4: 0x5591dd9d1a04 main at /home/max/src/test/test.cc:103
5: 0x7f3c1845cb97 __libc_start_main at ../csu/libc-start.c:344
6: 0x5591dd9d17aa _start
For comparison, backtrace_symbols_fd output for the same stacktrace is least informative:
/home/max/src/test/debug/gcc/test(+0x192f)[0x5601c5a2092f]
/usr/lib/x86_64-linux-gnu/libstdc++.so.6(+0x92ae5)[0x7f95184f5ae5]
/usr/lib/x86_64-linux-gnu/libstdc++.so.6(_ZSt9terminatev+0x10)[0x7f95184f5b20]
/usr/lib/x86_64-linux-gnu/libstdc++.so.6(__cxa_throw+0x43)[0x7f95184f5d53]
/home/max/src/test/debug/gcc/test(+0x1ae7)[0x5601c5a20ae7]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe6)[0x7f9518093b96]
/home/max/src/test/debug/gcc/test(+0x1849)[0x5601c5a20849]
In a production version (as well as C language version) you may like to make this code extra robust by replacing boost::core::demangle, std::string and std::cout with their underlying calls.
You can also override __cxa_throw to capture the stacktrace when an exception is thrown and print it when the exception is caught. By the time it enters catch block the stack has been unwound, so it is too late to call backtrace, and this is why the stack must be captured on throw which is implemented by function __cxa_throw. Note that in a multi-threaded program __cxa_throw can be called simultaneously by multiple threads, so that if it captures the stacktrace into a global array that must be thread_local.
You can also make the stack trace printing function async-signal safe, so that you can invoke it directly from your SIGSEGV, SIGBUS signal handlers (which should use their own stacks for robustness). Obtaining function name, source file and line number using libdwfl from a signal handler may fail because it is not async-signal safe or if the address space of the process has been substantially corrupted, but in practice it succeeds 99% of the time (I haven't seen it fail).
To summarize, a complete production-ready library for automatic stacktrace output should:
Capture the stacktrace on throw into thread-specific storage.
Automatically print the stacktrace on unhandled exceptions.
Print the stacktrace in async-signal-safe manner.
Provide a robust signal handler function which uses its own stack that prints the stacktrace in a async-signal-safe manner. The user can install this function as a signal handler for SIGSEGV, SIGBUS, SIGFPE, etc..
The signal handler may as well print the values of all CPU registers at the point of the fault from ucontext_t signal function argument (may be excluding vector registers), a-la Linux kernel oops log messages.
Another answer to an old thread.
When I need to do this, I usually just use system() and pstack
So something like this:
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include <sstream>
#include <cstdlib>
void f()
{
pid_t myPid = getpid();
std::string pstackCommand = "pstack ";
std::stringstream ss;
ss << myPid;
pstackCommand += ss.str();
system(pstackCommand.c_str());
}
void g()
{
f();
}
void h()
{
g();
}
int main()
{
h();
}
This outputs
#0 0x00002aaaab62d61e in waitpid () from /lib64/libc.so.6
#1 0x00002aaaab5bf609 in do_system () from /lib64/libc.so.6
#2 0x0000000000400c3c in f() ()
#3 0x0000000000400cc5 in g() ()
#4 0x0000000000400cd1 in h() ()
#5 0x0000000000400cdd in main ()
This should work on Linux, FreeBSD and Solaris. I don't think that macOS has pstack or a simple equivalent, but this thread seems to have an alternative.
If you are using C, then you will need to use C string functions.
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
void f()
{
pid_t myPid = getpid();
/*
length of command 7 for 'pstack ', 7 for the PID, 1 for nul
*/
char pstackCommand[7+7+1];
sprintf(pstackCommand, "pstack %d", (int)myPid);
system(pstackCommand);
}
I've used 7 for the max number of digits in the PID, based on this post.
There is no standardized way to do that. For windows the functionality is provided in the DbgHelp library
You can use the Boost libraries to print the current callstack.
#include <boost/stacktrace.hpp>
// ... somewhere inside the `bar(int)` function that is called recursively:
std::cout << boost::stacktrace::stacktrace();
Man here: https://www.boost.org/doc/libs/1_65_1/doc/html/stacktrace.html
I know this thread is old, but I think it can be useful for other people. If you are using gcc, you can use its instrument features (-finstrument-functions option) to log any function call (entry and exit). Have a look at this for more information: http://hacktalks.blogspot.fr/2013/08/gcc-instrument-functions.html
You can thus for instance push and pop every calls into a stack, and when you want to print it, you just look at what you have in your stack.
I've tested it, it works perfectly and is very handy
UPDATE: you can also find information about the -finstrument-functions compile option in the GCC doc concerning the Instrumentation options: https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html
You can implement the functionality yourself:
Use a global (string)stack and at start of each function push the function name and such other values (eg parameters) onto this stack; at exit of function pop it again.
Write a function that will printout the stack content when it is called, and use this in the function where you want to see the callstack.
This may sound like a lot of work but is quite useful.
Of course the next question is: will this be enough ?
The main disadvantage of stack-traces is that why you have the precise function being called you do not have anything else, like the value of its arguments, which is very useful for debugging.
If you have access to gcc and gdb, I would suggest using assert to check for a specific condition, and produce a memory dump if it is not met. Of course this means the process will stop, but you'll have a full fledged report instead of a mere stack-trace.
If you wish for a less obtrusive way, you can always use logging. There are very efficient logging facilities out there, like Pantheios for example. Which once again could give you a much more accurate image of what is going on.
You can use Poppy for this. It is normally used to gather the stack trace during a crash but it can also output it for a running program as well.
Now here's the good part: it can output the actual parameter values for each function on the stack, and even local variables, loop counters, etc.
You can use the GNU profiler. It shows the call-graph as well! the command is gprof and you need to compile your code with some option.
Is there any way to dump the call stack in a running process in C or C++ every time a certain function is called?
No there is not, although platform-dependent solutions might exist.

global variable always initialized zero

I've been writing an OS using this tutorial. I am at the part where
the boot loader is completed and C is used for programming (and then linked together ...). But that just as a note, I believe the problem I have is related to gcc.
I build an i386-elf cross compiler for the OS. And everything works fine, I can execute my code everything works. Except that all global variables are initialized zero, although I provided a default value.
int test_var = 1234;
// yes, void main() is correct (the boot-loader will call this)
void main() {}
If I debug this code with GDB, I get: (gcc-7.1.0, target: i328-elf)
(gdb) b main
Breakpoint 1 at 0x1554: file src/kernel/main.c, line 11.
(gdb) c
Continuing.
Breakpoint 1, main () at src/kernel/main.c:11
11 void main() {
(gdb) p test_var
$1 = 0
If i run the same code on my local machine (gcc-6.3.0, target: x86_64), it prints 1234.
My question is: Did I misconfigure gcc, is this a mistake in my OS, is this a known problem? I couldn't find anything about it.
My entire source-code: link
I use the following commands to compile my stuff:
# ...
i386-elf-gcc -g -ffreestanding -Iinclude/ -c src/kernel/main.c -o out/kernel/main.o
# ...
i386-elf-ld -e 0x1000 -Ttext 0x1000 -o out/kernel.elf out/kernel_entry.o out/kernel/main.o # some other stuff ...
i386-elf-objcopy -O binary out/kernel.elf out/kernel.bin
cat out/boot.bin out/kernel.bin > out/os.bin
qemu-system-i386 -drive "format=raw,file=out/os.bin"
EDIT: As #EugeneSh. suggested here some logic to make sure, that it's not removed:
#include <cpu/types.h>
#include <cpu/isr.h>
#include <kernel/print.h>
#include <driver/vga.h>
int test_var = 1234;
void main() {
vga_text_init();
switch (test_var) {
case 1234: print("That's correct"); break;
case 0: print("It's zero"); break;
// I don't have a method like atoi() in place, I would use
// GDB to get the value
default: print("It's something else");
}
}
Sadly it prints It's zero
Compiler never clears uninitialized global variables to zero, its logic in built inside loader,
So when you allocate memory for data segment then it size contains bss section also. So you have to check bss section offset, alignment & size withing data segment and memset() them to '0'.
As you are writing your OS so may be all the library routines are not available so better write memset() function using assembly.

Threaded shared library for non threaded application

I have some application for which I need to write extension using shared library. In my shared library I need to use threads. And main application neither uses threads neither linked with threads library (libpthread.so, for example).
As first tests showed my library causes crashes of the main application. And if i use LD_PRELOAD hack crashes goes away:
LD_PRELOAD=/path/to/libpthread.so ./app
The only OS where i have no segfaults without LD_PRELOAD hack is OS X. On other it just crashes. I tested: Linux, FreeBSD, NetBSD.
My question is: is there a way to make my threaded shared library safe for non-threaded application without changing of the main application and LD_PRELOAD hacks?
To reproduce the problem i wrote simple example:
mylib.c
#include <pthread.h>
#include <assert.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *_thread(void *arg) {
int i;
struct addrinfo *res;
for (i=0; i<10000; i++) {
if (getaddrinfo("localhost", NULL, NULL, &res) == 0) {
if (res) freeaddrinfo(res);
}
}
pthread_mutex_lock(&mutex);
printf("Just another thread message!\n");
pthread_mutex_unlock(&mutex);
return NULL;
}
void make_thread() {
pthread_t tid[10];
int i, rc;
for (i=0; i<10; i++) {
rc = pthread_create(&tid[i], NULL, _thread, NULL);
assert(rc == 0);
}
void *rv;
for (i=0; i<10; i++) {
rc = pthread_join(tid[i], &rv);
assert(rc == 0);
}
}
main.c
#include <stdio.h>
#include <dlfcn.h>
int main() {
void *mylib_hdl;
void (*make_thread)();
mylib_hdl = dlopen("./libmy.so", RTLD_NOW);
if (mylib_hdl == NULL) {
printf("dlopen: %s\n", dlerror());
return 1;
}
make_thread = (void (*)()) dlsym(mylib_hdl, "make_thread");
if (make_thread == NULL) {
printf("dlsym: %s\n", dlerror());
return 1;
}
(*make_thread)();
return 0;
}
Makefile
all:
cc -pthread -fPIC -c mylib.c
cc -pthread -shared -o libmy.so mylib.o
cc -o main main.c -ldl
clean:
rm *.o *.so main
And all together: https://github.com/olegwtf/sandbox/tree/bbbf76fdefe4bacef8a0de7a2475995719ae0436/threaded-so-for-non-threaded-app
$ make
cc -pthread -fPIC -c mylib.c
cc -pthread -shared -o libmy.so mylib.o
cc -o main main.c -ldl
$ ./main
*** glibc detected *** ./main: double free or corruption (fasttop): 0x0000000001614c40 ***
Segmentation fault
$ ldd libmy.so | grep thr
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fe7e2591000)
$ LD_PRELOAD=/lib/x86_64-linux-gnu/libpthread.so.0 ./main
Just another thread message!
Just another thread message!
Just another thread message!
Just another thread message!
Just another thread message!
Just another thread message!
Just another thread message!
Just another thread message!
Just another thread message!
Just another thread message!
My question is: is there a way to make my threaded shared library safe
for non-threaded application without changing of the main application
and LD_PRELOAD hacks?
No, those are the two ways you can make it work. With neither in place, your program is invalid.
dlopen is supposed to do the right thing, and to open all the libraries your own .so depends upon.
In fact, your code is working for me if I comment out the address lookup code that you placed inside your thread function. So loading the pthread library works perfectly.
And if I run the code including the lookup, valgrind shows me that the crash is below getaddrinfo.
So the problem is not that the libraries aren't loaded, somehow their initialization code is not executed or not in the right order.
gdb helped to understand what's goin on with this example.
After 3 tries gdb showed that app always crashed at rewind.c line 36 inside libc. Since tests were run on Debian 7, libc implementation is eglibc. And here you can see line 36 of rewind.c:
http://www.eglibc.org/cgi-bin/viewvc.cgi/branches/eglibc-2_13/libc/libio/rewind.c?annotate=12752
_IO_acquire_lock() is a macros and after grepping eglibc source I found 2 places where it is defined:
bits/stdio-lock.h line 49: http://www.eglibc.org/cgi-bin/viewvc.cgi/branches/eglibc-2_13/libc/bits/stdio-lock.h?annotate=12752
sysdeps/pthread/bits/stdio-lock.h line 91: http://www.eglibc.org/cgi-bin/viewvc.cgi/branches/eglibc-2_13/libc/nptl/sysdeps/pthread/bits/stdio-lock.h?annotate=12752
Comment for first says Generic version and for second NPTL version, where NTPL is Native POSIX Thread Library. So in few words first defines non-threaded implementation for this and several other macroses and second threaded implementation.
When our main application is not linked with pthreads it starts and loads this first non-threaded implementation of _IO_acquire_lock() and others macroses. Then it opens our threaded shared library and executes function from it. And this function uses already loaded and non thread safe version of _IO_acquire_lock(). However in fact should use threads compatible version defined by pthreads. This is where segfault occures.
This is how it works on Linux. On *BSD situation is even more sad. On FreeBSD your program will hang up immediately after your threaded library will try to create new thread. On NetBSD instead of hang up program will be terminated with SIGABRT.
So answering to the main question: is it possible to use threaded shared library from application not linked with pthreads?
In general -- no. And particularly this depends on libc implementation. For OS X, for example, this will work without any problems. For Linux this will work if you'll not use libc functions that uses such special macroses redefined by pthreads. But how to know which uses? Ok, you can make 1+1, this looks safe. On *BSD your program will crash or hang up immediately, no matter what your thread do.

editline/history.h and editline/readline.h not found/working on macOS when trying to compile with developer tools installed already

I am working on this tutorial on building your own LISP (http://www.buildyourownlisp.com/chapter4_interactive_prompt) and for some reason when I try to compile I get this:
REPL.c:4:10: fatal error: 'editline/readline.h' file not found
#include <editline/history.h>
^
1 error generated.
I have installed the macOS developer tools, and brew is showing readline is installed and it doesn't know what to do when I try brew install editline.
This is my code:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <editline/readline.h>
4 #include <editline/history.h>
5
6 int main(int argc, char** argv) {
7
8 /* version/exit info */
9 puts("Edward Version 0.0.1");
10 puts("Press Ctrl+c to Exit\n");
11
12 /* endless loop for main REPL */
13 while (1) {
14 /* output prompt and read line */
15 char* input = readline("lispy> ");
16
17 /* put input in history */
18 add_history(input);
19
20 /* Echo input back */
21 printf("No you're a %s\n", input);
22
23 /* free input */
24 free(input);
25 }
26 return 0;
27 }
It is obviously very basic, but I really want to get this project rolling so I'm hoping I can figure this out. This is what I'm using to compile:
cc -std=c99 -Wall REPL.c -ledit -o REPL
Include only
#include <editline/readline.h>
which should exist if the command line tools are installed. This file contains the
"readline wrapper" for libedit, including the history functions as well.
An include file <editline/history.h> does not exist on OS X.
I tested your code with that modification, and it compiled and ran without problems.
Using OSX Yosemite. I removed #include<editline/history.h>
and then used cc -std=c99 -Wall test.c -ledit -o test
Works fine now
I'm on El Capitan,
Remove #include <editline/history.h>,
and use cc -std=c99 -Wall test.c -ledit -o test works for me.
Add the flag -ledit before the output flad, it's a linking process, allows the compiler to directly embed calls to editline in your program. Or, you'll get the below error message,
Undefined symbols for architecture x86_64:
"_add_history", referenced from:
_main in prompt-086f90.o
"_readline", referenced from:
_main in prompt-086f90.o
ld: symbol(s) not found for architecture x86_64
I'm on Ubuntu 14.04.
try this:
sudo apt-get install libeditline-dev
and include like this:
#include <editline.h>
finally compile like this:
add -leditline in the flag
I hope this can help.
I'm on OSX Mavericks and removing the line worked for me:
#include <editline/history.h>
The solution for those following along on FreeBSD (might work on other Unices as well):
#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
...
And run:
$ cc test.c -Wall -std=c99 -lreadline -o test
Without "-lreadline" in the compile step it is not linked in and you will get errors about undefined reference to "readline" function.
I started in on Build your own list and ran into the same problem.
None of the above answers worked for me. After a little research I found out that macOs doesn't have the gnu readline library that provides the readline functions, Different versions of MacOs provide emulation of readline using a library called editline. to begin...
man editline
#include <histedit.h>
Ok, editline gives you some structs for line input and history,
and functions to operate on them. First you have to instantiate these structs. The documentation for editline is not very helpful because it doesn't contain any examples. Apple makes the header file available so that helps a little. http://www.opensource.apple.com/source/libedit/libedit-13/src/histedit.h
I am new to this and it was still pretty confusing to me. there is some version of the source code to libedit available as a debian package. Fortunately someone wiser than I has already dug into it and implemented a command line using lbedit. His code is here: https://www.cs.utah.edu/~bigler/code/libedit.html.
I took Mr Bigler's code, and the code from Build your own list, and put them together to get this.
/* repl-macos.c
* Repl code example from builyourownlisp.com
* Modified by NB aug 2017
* Code example for editline from
* www.cs.utah.edu/~bigler/code/libedit.html
*/
#include <stdio.h>
#include <string.h>
#include <histedit.h>
char* prompt(EditLine *e){
return "lispy> ";
}
int main(int argc, char** argv){
EditLine *el; // Line editor state
History *herstory; // the rest is history
// Temp Variables
int count;
const char *usrin;
int keepreading = 1;
HistEvent ev;
// Initialize the editline state
el = el_init(argv[0], stdin, stdout, stderr);
el_set(el, EL_PROMPT, &prompt);
el_set(el, EL_EDITOR, "emacs");
// Initialize history
herstory = history_init();
if(!herstory){
fprintf(stderr, "Couldn't initialize history\n");
return 1;
}
//set history size
history(herstory, &ev, H_SETSIZE, 800);
// Set up the call back functions for history functionality
el_set(el, EL_HIST, history, herstory);
puts("Begin moLisp interpreter");
puts("Type 'exit' at prompt to exit");
while(keepreading){
usrin = el_gets(el, &count);
// add the command to the history, and echo it back to the user
if(count > 0){
history(herstory, &ev, H_ENTER, usrin);
if(strcmp(usrin, "exit\n"))
printf("No, You're a %s", usrin);
else{
puts("bye");
--keepreading;
}
}
}
// Clean up memory
// by freeing the memory pointed to within the structs that
// libedit has created.
history_end(herstory);
el_end(el);
return 0;
}
Notice: The instantiation of the structs that are used happens outside of
the while loop, and so do the functions that free the memory those structs are using. Because of this, I added the command to exit, otherwise I think there's a memory leak if the only way to exit the while loop is by interrupting the program. To compile:
gcc repl-macos.c -ledit -Wall -o repl-edit
-ledit is needed to link editline
If it has any relevance, I am using macOs 10.4.11
and here's my compiler, output of
gcc --version
powerpc-apple-darwin8-gcc-4.0.0 (GCC) 4.0.0 20041026 (Apple Computer, Inc. build 4061)
Now the only problem with this, and the book points this out, is that
c-code is supposed to be portable and this isn't. The next step would be to add preprocessor directives so that it uses readline on linux and editline on macos.
If you are on ubuntu add the editline library
sudo apt-get install libtedit-dev
On Debian Buster 10, I had to install the package with:
sudo apt install libeditline-dev
Instead of:
#include <editline/readline.h>
#include <editline/history.h>
I just included:
#include <editline.h>
ran the program with -leditline flag and worked perfectly.

Resources