Getting back trace for ARC platform from signal handler context - c

I want to catch SIGSEGV and print the back trace in the logs before my program exits. This is to analyze the crash at a later point of time. I am working on a software which runs on multiple platforms. On x86 platform I can do this easily by using glibc backtrace() function. But the same is not available for MIPS and ARC platforms. I am able to print the back trace for MIPS architecture as explained here
I want to do something similar for ARC platform as well. It would be great help if someone can give some data points on where I can get similar details.
Edit:
After some research I figured out that in ARC platform for a function call, stack is not allocated at once but allocated in parts. (Correct me if I am wrong. I went through the object dump and figured this out.) So I feel it will be hard to do binary code parsing in this case as opposed to MIPS.
Another approach would be to write some inline assembly in C and get stack pointer, frame pointer and branch link register content (blink) and then try to unwind the stack using stack & frame size and print value of blink in each frame. But I am not able to find the frame size.
Here is a sample code to get FP,SP,BLINK.
int func2(int func2_arg)
{
unsigned long *stack2_addr;
unsigned long *frame2_addr;
unsigned long *blink2_addr;
printf("\nFunc : %s\n",__FUNCTION__);
__asm__ __volatile__ ("st sp,[sp,4]");
printf("Stack pointer: %d\n",stack2_addr);
__asm__ __volatile__ ("st blink,[sp,12]");
printf("Blink: %d \n",blink2_addr);
__asm__ __volatile__ ("st fp,[sp,8]");
printf("Frame pointer2: %d, %d\n",frame2_addr,*frame2_addr);
return 0;
}
Yes this is not good coding! I have made many assumptions. But for me it is fine as far as it is working on my board. :)
Any help would be greatly appreciated. Here is another reference on ARC gcc.

Finally found some open source code (Apache license) which does what was required. Here is the code which works.
Sorry about the big code post.
/*
* Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <config.h>
#include "backtrace.h"
#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include "compiler.h"
#include "vlog.h"
VLOG_DEFINE_THIS_MODULE(backtrace);
#ifdef HAVE_BACKTRACE
#include <execinfo.h>
void
backtrace_capture(struct backtrace *b)
{
void *frames[BACKTRACE_MAX_FRAMES];
int i;
b->n_frames = backtrace(frames, BACKTRACE_MAX_FRAMES);
for (i = 0; i < b->n_frames; i++) {
b->frames[i] = (uintptr_t) frames[i];
}
}
#elif __GNUC__
static uintptr_t
get_max_stack(void)
{
static const char file_name[] = "/proc/self/maps";
char line[1024];
int line_number;
FILE *f;
f = fopen(file_name, "r");
if (f == NULL) {
VLOG_WARN("opening %s failed: %s", file_name, strerror(errno));
return -1;
}
for (line_number = 1; fgets(line, sizeof line, f); line_number++) {
if (strstr(line, "[stack]")) {
uintptr_t end;
if (sscanf(line, "%*x-%"SCNxPTR, &end) != 1) {
VLOG_WARN("%s:%d: parse error", file_name, line_number);
continue;
}
fclose(f);
return end;
}
}
fclose(f);
VLOG_WARN("%s: no stack found", file_name);
return -1;
}
static uintptr_t
stack_high(void)
{
static uintptr_t high;
if (!high) {
high = get_max_stack();
}
return high;
}
static uintptr_t
stack_low(void)
{
uintptr_t low = (uintptr_t) &low;
return low;
}
static bool
in_stack(void *p)
{
uintptr_t address = (uintptr_t) p;
return address >= stack_low() && address < stack_high();
}
void
backtrace_capture(struct backtrace *backtrace)
{
void **frame;
size_t n;
n = 0;
for (frame = __builtin_frame_address(1);
frame != NULL && in_stack(frame) && frame[0] != NULL
&& n < BACKTRACE_MAX_FRAMES;
frame = frame[0])
{
backtrace->frames[n++] = (uintptr_t) frame[1];
}
backtrace->n_frames = n;
}
#else /* !HAVE_BACKTRACE && !__GNUC__ */
void
backtrace_capture(struct backtrace *backtrace)
{
backtrace->n_frames = 0;
}
#endif
Hope this will be useful for someone else also !

Related

On ARM macOS when explicitly raise()-ing a signal, some return addresses are garbled on the stack

Here's a simple program for ARM macOS that installs a signal handler for SIGSEGV, then generates one. In the signal handler function, the stack is walked with the usual frame pointer chasing algorithm, then the symbolized version is printed out:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <execinfo.h>
#include <stdlib.h>
void handler(int signum, siginfo_t* siginfo, void* context)
{
__darwin_ucontext* ucontext = (__darwin_ucontext*) context;
__darwin_mcontext64* machineContext = ucontext->uc_mcontext;
uint64_t programCounter = machineContext->__ss.__pc;
uint64_t framePointer = machineContext->__ss.__fp;
void* bt[100];
int n = 0;
while (framePointer != 0) {
bt[n] = (void*)programCounter;
programCounter = *(uint64_t*)(framePointer + 8);
framePointer = *(uint64_t*)(framePointer);
++n;
}
char** symbols = backtrace_symbols(bt, n);
printf ("Call stack:\n");
for (int i = 0; i < n; ++i) {
printf ("\t %s\n", symbols[i]);
}
free (symbols);
abort ();
}
void Crash ()
{
raise (SIGSEGV);
//*(volatile int*)0 = 0;
}
int main()
{
struct sigaction sigAction;
sigAction.sa_sigaction = handler;
sigAction.sa_flags = SA_SIGINFO;
sigaction (SIGSEGV, &sigAction, nullptr);
Crash ();
}
This works fine when a "regular" SIGSEGV happens, but when it's raised explicitly, return values on the stack seem garbled, specifically, the upper part seems to contain garbage:
Call stack:
0 libsystem_kernel.dylib 0x0000000185510e68 __pthread_kill + 8
1 libsystem_c.dylib 0x116a000185422e14 raise + [...] // Should be 0x0000000185422e14
2 SignalHandlerTest 0x8f6a000104bc3eb8 _Z5Crashv + [...] // Should be 0x0000000104bc3eb8
3 SignalHandlerTest 0x0000000104bc3ef8 main + 56
4 libdyld.dylib 0x0000000185561450 start + 4
The behavior is the same regardless of which signal is raised. What am I missing?
As #Codo has correctly identified, this is PAC.
The upper bits of the address are not garbled, but rather contain a salted hash of the register's lower bits.
And contrary to your claims, this happens with regular segfaults too. For example, calling fprintf(NULL, "a"); results in:
Call stack:
0 libsystem_c.dylib 0x000000019139d8a0 flockfile + 28
1 libsystem_c.dylib 0x1d550001913a5870 vfprintf_l + 2113595600120315944
2 libsystem_c.dylib 0x341c80019139efd0 fprintf + 3755016926808506440
3 t 0x5f29000100483e9c Crash + 6857011907648290844
4 t 0x0000000100483edc main + 56
5 libdyld.dylib 0x00000001914b1430 start + 4
This is because all system binaries, including libraries, are compiled for the arm64e ABI and will make use of PAC. Now, your binary is running as a regular old arm64 binary and would crash if it passed an unsigned function pointer to a library function, or got a signed one returned. So the kernel actually disables 3 of the 4 keys that your process can use (IA, IB, DA and DB). But one of those, IB, is used solely for stack frames and so that one is left enabled even in arm64 binaries.
The reason why some return addresses are still not signed though is:
The main + 56 and start + 4 were pushed by your code, which is arm64 and hence doesn't sign them.
The flockfile + 28 is the instruction that crashed, whose address was never pushed to the stack, but extracted from the thread state.
So everything's working exactly as it's supposed to.
Edit:
After attempting to use this to aid me in debugging myself, I find the PAC'ed addresses to be annoying after all. You commented about ptrauth_strip in ptrauth.h, but that will actually not work inside an arm64 process (it's aliased to a macro that does nothing), nor will __builtin_ptrauth_strip (the compiler will error out).
The compiler won't even let you use a raw xpaci instruction when targeting arm64, but nothing on the hardware level prevents the instruction from working, so you can still manually inject the opcode.
Based on this, I wrote a signal handler that properly strips PAC signatures from an arm64 process:
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <execinfo.h>
#ifdef __arm64__
extern void* xpaci(uint64_t pc);
__asm__
(
"_xpaci:\n"
" mov x1, x30\n"
" mov x30, x0\n"
" .4byte 0xd50320ff\n" // xpaclri
" mov x0, x30\n"
" ret x1\n"
);
#else
static inline void* xpaci(uint64_t pc)
{
return (void*)pc;
}
#endif
static void handler(int signum, siginfo_t *siginfo, void *ctx)
{
_STRUCT_MCONTEXT64 *mctx = ((_STRUCT_UCONTEXT*)ctx)->uc_mcontext;
#ifdef __arm64__
uint64_t orig_pc = mctx->__ss.__pc;
uint64_t orig_fp = mctx->__ss.__fp;
#elif defined(__x86_64__)
uint64_t orig_pc = mctx->__ss.__rip;
uint64_t orig_fp = mctx->__ss.__rbp;
#else
# error "Unknown arch"
#endif
uint64_t pc = orig_pc;
uint64_t fp = orig_fp;
size_t n = 0;
while(1)
{
if(!xpaci(pc))
{
break;
}
++n;
if(!fp)
{
break;
}
pc = ((uint64_t*)fp)[1];
fp = ((uint64_t*)fp)[0];
}
void **bt = malloc(n * sizeof(void*));
if(!bt)
{
fprintf(stderr, "malloc: %s\n", strerror(errno));
exit(-1);
}
pc = orig_pc;
fp = orig_fp;
for(size_t i = 0; i < n; ++i)
{
bt[i] = xpaci(pc);
if(!fp)
{
break;
}
pc = ((uint64_t*)fp)[1];
fp = ((uint64_t*)fp)[0];
}
char **sym = backtrace_symbols(bt, n);
fprintf(stderr, "Caught signal with call stack:\n");
for(size_t i = 0; i < n; ++i)
{
fprintf(stderr, "%s\n", sym[i]);
}
free(sym);
free(bt);
exit(-1);
}
It uses xpaclri rather than xpaci, since the former is a NOP on arm64 (non-arm64e) hardware while the latter would be undefined.

Segmentation fault with -O3 flag [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
Edit: I am really sorry if I have wasted time of your guys, I was running out of time when posting this problem. Here comes the code that I have done my best to minimize it
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum Error {
ERROR_UNRESOLVED_NAME = 1,
ERROR_CANNOT_OPEN_FILE,
ERROR_NO_ARGV,
ERROR_UNRECOGNIZED_SYMBOL,
ERROR_UNCOMPLETED_SENTENCE,
ERROR_RECURSIVE_SELF
};
struct _Piece;
typedef struct _Piece *(*PieceFunc)(struct _Piece *, void *);
struct _Piece {
PieceFunc function;
void *backpack;
};
typedef struct _Piece Piece;
Piece *piece_create(PieceFunc func, void *pack) {
Piece *piece = malloc(sizeof(Piece));
piece->function = func;
piece->backpack = pack;
return piece;
}
typedef struct _Record {
char *name;
int name_len;
Piece *piece;
struct _Record *previous;
} Record;
Record *record_register(Record *pre, char *name, int name_len, Piece *piece) {
Record *record = malloc(sizeof(Record));
record->name = name;
record->name_len = name_len;
record->piece = piece;
record->previous = pre;
return record;
}
typedef struct {
char *file_name;
char *source;
int length;
int current;
int line;
int column;
} Source;
Source *source_create(char *s, int len, char *file_name) {
Source *source = malloc(sizeof(Source));
source->source = s;
source->file_name = file_name;
source->length = len;
source->current = 0;
source->line = source->column = 1;
return source;
}
Piece *apply(Piece *caller, Piece *callee) {
return caller->function(callee, caller->backpack);
}
// Part 3, internals
Piece *internal_self(Piece *callee, void *backpack) {
if (callee->function == internal_self) {
fprintf(stderr,
"recursive `self` calling between two pieces\n"
"piece 1 backpack: %p\n"
"piece 2: %p backpack: %p",
backpack, callee, callee->backpack);
exit(ERROR_RECURSIVE_SELF);
}
return apply(callee, piece_create(internal_self, backpack));
}
Piece *internal_put(Piece *callee, void *backpack) {
int *p_char = callee->backpack;
putchar(*p_char);
return piece_create(internal_self, NULL);
}
Source *main_create_source(char *file_name) {
FILE *source_file = fopen(file_name, "r");
if (!source_file) {
fprintf(stderr, "cannot open file \"%s\"\n", file_name);
exit(ERROR_CANNOT_OPEN_FILE);
}
char *source = NULL;
int length = 0;
while (true) {
char *line = NULL;
int line_len = 0;
line_len = (int)getline(&line, (size_t *)&line_len, source_file);
if (line_len < 0) {
break;
}
if (source == NULL) {
source = line;
} else {
source = realloc(source, sizeof(char) * (length + line_len + 1));
strcat(source, line);
// free(line);
}
length += line_len;
}
fclose(source_file);
return source_create(source, length, file_name);
}
#define MAIN_REGISTER_INTERNAL(record, name, func) \
record = record_register(record, name, sizeof(name) - 1, \
piece_create(func, NULL)); \
printf("%p %p\n", record, record->previous);
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "please specify source file by command line argument\n");
exit(ERROR_NO_ARGV);
}
Record *r = NULL;
MAIN_REGISTER_INTERNAL(r, "put", internal_put);
printf("main %p\n", r);
Source *s = main_create_source(argv[1]);
printf("main %p\n", r);
}
At first, the program crashed with a segmentation fault, I located the bad access code line, which have been deleted in this code demo. I figure out the original bug is that variable r in main would unexpected change after an unrelated calling to main_create_source, which would be demonstrated like this (save this code file as foo.c)
$ cc -O0 -g foo.c
$ ./a.out futaba_test.ftb
0x7fc0024025b0 0x0
main 0x7fc0024025b0
main 0x7fc0024025b0
$ cc -O3 -g foo.c
$ ./a.out futaba_test.ftb
0x7fe861c025b0 0x0
main 0x7fe861c025b0
main 0x7fe800000000
The behavior varied when changing optimization level. It has nothing todo with EOF since I have removed it, and in my opinion the memory for strcat's destination is rich enough. Thanks for any help.
By the way if there is any requirement to point out the purpose of this snippet. This is an interpreter for a minimal language I am working on. It is able to evaluate small source code snippet at the time and this is the first time I have tried to build it with -O3. The bug will only disappear without any level optimization.
(The following is the original post and is able to be ignored.)
I have this code file. When compiling with cc -O0 futaba.c, and running it with ./a.out futaba_test.ftb, the result will be
0x7fba60c025b0 0x0
0x7fba60c025e0 0x7fba60c025b0
0x7fba60c02610 0x7fba60c025e0
0x7fba60c02640 0x7fba60c02610
0x7fba60c02670 0x7fba60c02640
0x7fba60c026b0 0x7fba60c02670
0x7fba60c026d0 0x7fba60c026b0
0x7fba60c02700 0x7fba60c026d0
0x7fba60c02730 0x7fba60c02700
main 0x7fba60c02730
main 0x7fba60c02730
A%
(Zsh add the postfix %) everything is going well. But when compiling with -O3 rather than -O0, than result will be
0x7f8f274025b0 0x0
0x7f8f274025e0 0x7f8f274025b0
0x7f8f27402610 0x7f8f274025e0
0x7f8f27402640 0x7f8f27402610
0x7f8f27402670 0x7f8f27402640
0x7f8f274026b0 0x7f8f27402670
0x7f8f274026d0 0x7f8f274026b0
0x7f8f27402700 0x7f8f274026d0
0x7f8f27402730 0x7f8f27402700
main 0x7f8f27402730
main 0x7f8f00000000
[1] 27811 segmentation fault ./a.out futaba_test.ftb
The last two main line print different address, and the second one is not valid, which cause the stack overflow bug later in record_resolve function.
What is the problem?
That's a lot of code, but here's at least a flag:
char source_fetch(Source *s) {
return s->current == s->length ? EOF : s->source[s->current];
}
This forces EOF into a char, which is a very bad idea. That's why all standard C functions that can return EOF (like getchar() return int.
No idea what an optimizing compiler can make out of that, but once you factor in code that waits for EOF using that ... it's smelly.
Note: this is perhaps bad form as an answer; but it's pointing out a concrete problem with the code.
Also none of the heap allocations seems to have code looking for NULL being returned; that's a bit scary too.

Overload symbols of running process (LD_PRELOAD attachment)

I'm working on a heap profiler for Linux, called heaptrack. Currently, I rely on LD_PRELOAD to overload various (de-)allocation functions, and that works extremely well.
Now I would like to extend the tool to allow runtime attaching to an existing process, which was started without LD_PRELOADing my tool. I can dlopen my library via GDB just fine, but that won't overwrite malloc etc. I think, this is because at that point the linker already resolved the position dependent code of the already running process - correct?
So what do I do instead to overload malloc and friends?
I am not proficient with assembler code. From what I've read so far, I guess I'll somehow have to patch malloc and the other functions, such that they first call back to my trace function and then continue with their actual implementation? Is that correct? How do I do that?
I hope there are existing tools out there, or that I can leverage GDB/ptrace for that.
Just for the lulz, another solution without ptracing your own process or touching a single line of assembly or playing around with /proc. You only have to load the library in the context of the process and let the magic happen.
The solution I propose is to use the constructor feature (brought from C++ to C by gcc) to run some code when a library is loaded. Then this library just patch the GOT (Global Offset Table) entry for malloc. The GOT stores the real addresses for the library functions so that the name resolution happen only once. To patch the GOT you have to play around with the ELF structures (see man 5 elf). And Linux is kind enough to give you the aux vector (see man 3 getauxval) that tells you where to find in memory the program headers of the current program. However, better interface is provided by dl_iterate_phdr, which is used below.
Here is an example code of library that does exactly this when the init function is called. Although the same could probably be achieved with a gdb script.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <sys/auxv.h>
#include <elf.h>
#include <link.h>
#include <sys/mman.h>
struct strtab {
char *tab;
ElfW(Xword) size;
};
struct jmpreltab {
ElfW(Rela) *tab;
ElfW(Xword) size;
};
struct symtab {
ElfW(Sym) *tab;
ElfW(Xword) entsz;
};
/* Backup of the real malloc function */
static void *(*realmalloc)(size_t) = NULL;
/* My local versions of the malloc functions */
static void *mymalloc(size_t size);
/*************/
/* ELF stuff */
/*************/
static const ElfW(Phdr) *get_phdr_dynamic(const ElfW(Phdr) *phdr,
uint16_t phnum, uint16_t phentsize) {
int i;
for (i = 0; i < phnum; i++) {
if (phdr->p_type == PT_DYNAMIC)
return phdr;
phdr = (ElfW(Phdr) *)((char *)phdr + phentsize);
}
return NULL;
}
static const ElfW(Dyn) *get_dynentry(ElfW(Addr) base, const ElfW(Phdr) *pdyn,
uint32_t type) {
ElfW(Dyn) *dyn;
for (dyn = (ElfW(Dyn) *)(base + pdyn->p_vaddr); dyn->d_tag; dyn++) {
if (dyn->d_tag == type)
return dyn;
}
return NULL;
}
static struct jmpreltab get_jmprel(ElfW(Addr) base, const ElfW(Phdr) *pdyn) {
struct jmpreltab table;
const ElfW(Dyn) *dyn;
dyn = get_dynentry(base, pdyn, DT_JMPREL);
table.tab = (dyn == NULL) ? NULL : (ElfW(Rela) *)dyn->d_un.d_ptr;
dyn = get_dynentry(base, pdyn, DT_PLTRELSZ);
table.size = (dyn == NULL) ? 0 : dyn->d_un.d_val;
return table;
}
static struct symtab get_symtab(ElfW(Addr) base, const ElfW(Phdr) *pdyn) {
struct symtab table;
const ElfW(Dyn) *dyn;
dyn = get_dynentry(base, pdyn, DT_SYMTAB);
table.tab = (dyn == NULL) ? NULL : (ElfW(Sym) *)dyn->d_un.d_ptr;
dyn = get_dynentry(base, pdyn, DT_SYMENT);
table.entsz = (dyn == NULL) ? 0 : dyn->d_un.d_val;
return table;
}
static struct strtab get_strtab(ElfW(Addr) base, const ElfW(Phdr) *pdyn) {
struct strtab table;
const ElfW(Dyn) *dyn;
dyn = get_dynentry(base, pdyn, DT_STRTAB);
table.tab = (dyn == NULL) ? NULL : (char *)dyn->d_un.d_ptr;
dyn = get_dynentry(base, pdyn, DT_STRSZ);
table.size = (dyn == NULL) ? 0 : dyn->d_un.d_val;
return table;
}
static void *get_got_entry(ElfW(Addr) base, struct jmpreltab jmprel,
struct symtab symtab, struct strtab strtab, const char *symname) {
ElfW(Rela) *rela;
ElfW(Rela) *relaend;
relaend = (ElfW(Rela) *)((char *)jmprel.tab + jmprel.size);
for (rela = jmprel.tab; rela < relaend; rela++) {
uint32_t relsymidx;
char *relsymname;
relsymidx = ELF64_R_SYM(rela->r_info);
relsymname = strtab.tab + symtab.tab[relsymidx].st_name;
if (strcmp(symname, relsymname) == 0)
return (void *)(base + rela->r_offset);
}
return NULL;
}
static void patch_got(ElfW(Addr) base, const ElfW(Phdr) *phdr, int16_t phnum,
int16_t phentsize) {
const ElfW(Phdr) *dphdr;
struct jmpreltab jmprel;
struct symtab symtab;
struct strtab strtab;
void *(**mallocgot)(size_t);
dphdr = get_phdr_dynamic(phdr, phnum, phentsize);
jmprel = get_jmprel(base, dphdr);
symtab = get_symtab(base, dphdr);
strtab = get_strtab(base, dphdr);
mallocgot = get_got_entry(base, jmprel, symtab, strtab, "malloc");
/* Replace the pointer with our version. */
if (mallocgot != NULL) {
/* Quick & dirty hack for some programs that need it. */
/* Should check the returned value. */
void *page = (void *)((intptr_t)mallocgot & ~(0x1000 - 1));
mprotect(page, 0x1000, PROT_READ | PROT_WRITE);
*mallocgot = mymalloc;
}
}
static int callback(struct dl_phdr_info *info, size_t size, void *data) {
uint16_t phentsize;
data = data;
size = size;
printf("Patching GOT entry of \"%s\"\n", info->dlpi_name);
phentsize = getauxval(AT_PHENT);
patch_got(info->dlpi_addr, info->dlpi_phdr, info->dlpi_phnum, phentsize);
return 0;
}
/*****************/
/* Init function */
/*****************/
__attribute__((constructor)) static void init(void) {
realmalloc = malloc;
dl_iterate_phdr(callback, NULL);
}
/*********************************************/
/* Here come the malloc function and sisters */
/*********************************************/
static void *mymalloc(size_t size) {
printf("hello from my malloc\n");
return realmalloc(size);
}
And an example program that just loads the library between two malloc calls.
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
void loadmymalloc(void) {
/* Should check return value. */
dlopen("./mymalloc.so", RTLD_LAZY);
}
int main(void) {
void *ptr;
ptr = malloc(42);
printf("malloc returned: %p\n", ptr);
loadmymalloc();
ptr = malloc(42);
printf("malloc returned: %p\n", ptr);
return EXIT_SUCCESS;
}
The call to mprotect is usually useless. However I found that gvim (which is compiled as a shared object) needs it. If you also want to catch the references to malloc as pointers (which may allow to later call the real function and bypass yours), you can apply the very same process to the symbol table pointed to by the DT_RELA dynamic entry.
If the constructor feature is not available for you, all you have to do is resolve the init symbol from the newly loaded library and call it.
Note that you may also want to replace dlopen so that libraries loaded after yours gets patched as well. Which may happen if you load your library quite early or if the application has dynamically loaded plugins.
This can not be done without tweaking with assembler a bit. Basically, you will have to do what gdb and ltrace do: find malloc and friends virtual addresses in the process image and put breakpoints at their entry. This process usually involves temporary rewriting the executable code, as you need to replace normal instructions with "trap" ones (such as int 3 on x86).
If you want to avoid doing this yourself, there exists linkable wrapper around gdb (libgdb) or you can build ltrace as a library (libltrace). As ltrace is much smaller, and the library variety of it is available out of the box, it will probably allow you to do what you want at lower effort.
For example, here's the best part of the "main.c" file from the ltrace package:
int
main(int argc, char *argv[]) {
ltrace_init(argc, argv);
/*
ltrace_add_callback(callback_call, EVENT_SYSCALL);
ltrace_add_callback(callback_ret, EVENT_SYSRET);
ltrace_add_callback(endcallback, EVENT_EXIT);
But you would probably need EVENT_LIBCALL and EVENT_LIBRET
*/
ltrace_main();
return 0;
}
http://anonscm.debian.org/cgit/collab-maint/ltrace.git/tree/?id=0.7.3

tinyc compiler - libtcc, how to bound check?

im using libtcc to compile c code on the fly. Im going to use it on a cloud computer, to be used over the internet.
how do i use tinyc's built in memory and bound checker function?
heres an example that comes with the tinyc libtcc library?
any help would be great!
thank you!
/*
* Simple Test program for libtcc
*
* libtcc can be useful to use tcc as a "backend" for a code generator.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "libtcc.h"
/* this function is called by the generated code */
int add(int a, int b)
{
return a + b;
}
char my_program[] =
"int fib(int n)\n"
"{\n"
" if (n <= 2)\n"
" return 1;\n"
" else\n"
" return fib(n-1) + fib(n-2);\n"
"}\n"
"\n"
"int foo(int n)\n"
"{\n"
" printf(\"Hello World!\\n\");\n"
" printf(\"fib(%d) = %d\\n\", n, fib(n));\n"
" printf(\"add(%d, %d) = %d\\n\", n, 2 * n, add(n, 2 * n));\n"
" return 0;\n"
"}\n";
int main(int argc, char **argv)
{
TCCState *s;
int (*func)(int);
void *mem;
int size;
s = tcc_new();
if (!s) {
fprintf(stderr, "Could not create tcc state\n");
exit(1);
}
/* if tcclib.h and libtcc1.a are not installed, where can we find them */
if (argc == 2 && !memcmp(argv[1], "lib_path=",9))
tcc_set_lib_path(s, argv[1]+9);
/* MUST BE CALLED before any compilation */
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
if (tcc_compile_string(s, my_program) == -1)
return 1;
/* as a test, we add a symbol that the compiled program can use.
You may also open a dll with tcc_add_dll() and use symbols from that */
tcc_add_symbol(s, "add", add);
/* get needed size of the code */
size = tcc_relocate(s, NULL);
if (size == -1)
return 1;
/* allocate memory and copy the code into it */
mem = malloc(size);
tcc_relocate(s, mem);
/* get entry symbol */
func = tcc_get_symbol(s, "foo");
if (!func)
return 1;
/* delete the state */
tcc_delete(s);
/* run the code */
func(32);
free(mem);
return 0;
}
you can set bounds checking manually using:
s->do_bounds_check = 1; //s here is TCCState*
just make sure libtcc is compiled with CONFIG_TCC_BCHECK being defined.
you may also want to enable debugging using:
s->do_debug = 1;
the command line option -b does the exact same to enable bounds checking (it enables debugging as well).

How to make backtrace()/backtrace_symbols() print the function names?

The Linux specific backtrace() and backtrace_symbols() allows you to produce a call trace of the program. However, it only prints function addresses, not their names for my program. How can I make them print the function names as well ? I've tried compiling the program with -g as well as -ggdb. The test case below just prints this:
BACKTRACE ------------
./a.out() [0x8048616]
./a.out() [0x8048623]
/lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413]
./a.out() [0x8048421]
----------------------
I'd want the first 2 items to also show the function names, foo and main
Code:
#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
static void full_write(int fd, const char *buf, size_t len)
{
while (len > 0) {
ssize_t ret = write(fd, buf, len);
if ((ret == -1) && (errno != EINTR))
break;
buf += (size_t) ret;
len -= (size_t) ret;
}
}
void print_backtrace(void)
{
static const char start[] = "BACKTRACE ------------\n";
static const char end[] = "----------------------\n";
void *bt[1024];
int bt_size;
char **bt_syms;
int i;
bt_size = backtrace(bt, 1024);
bt_syms = backtrace_symbols(bt, bt_size);
full_write(STDERR_FILENO, start, strlen(start));
for (i = 1; i < bt_size; i++) {
size_t len = strlen(bt_syms[i]);
full_write(STDERR_FILENO, bt_syms[i], len);
full_write(STDERR_FILENO, "\n", 1);
}
full_write(STDERR_FILENO, end, strlen(end));
free(bt_syms);
}
void foo()
{
print_backtrace();
}
int main()
{
foo();
return 0;
}
The symbols are taken from the dynamic symbol table; you need the -rdynamic option to gcc, which makes it pass a flag to the linker which ensures that all symbols are placed in the table.
(See the Link Options page of the GCC manual, and / or the Backtraces page of the glibc manual.)
Use the addr2line command to map executable addresses to source code filename+line number. Give the -f option to get function names as well.
Alternatively, try libunwind.
The excellent Libbacktrace by Ian Lance Taylor solves this issue. It handles stack unwinding and supports both ordinary ELF symbols and DWARF debugging symbols.
Libbacktrace does not require exporting all symbols, which would be ugly, and ASLR does not break it.
Libbacktrace was originally part of the GCC distribution. Now, a standalone version can be found on Github:
https://github.com/ianlancetaylor/libbacktrace
the answer on the top has a bug
if ret == -1 and errno is EINTER you should try again, but not count ret as copied
(not going to make an account just for this, if you don't like it tough)
static void full_write(int fd, const char *buf, size_t len)
{
while (len > 0) {
ssize_t ret = write(fd, buf, len);
if ((ret == -1) {
if (errno != EINTR))
break;
//else
continue;
}
buf += (size_t) ret;
len -= (size_t) ret;
}
}
Boost backtrace
Very convenient because it prints both:
unmangled C++ function names
line numbers
automatically for you.
Usage summary:
#define BOOST_STACKTRACE_USE_ADDR2LINE
#include <boost/stacktrace.hpp>
std::cout << boost::stacktrace::stacktrace() << std::endl;
I have provided a minimal runnable example for it and many other methods at: print call stack in C or C++

Resources