Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

libunwind while unwinding a NULL IP

I am trying to use libunwind to crawl stacktraces from within my signal handler. The problem is that the frame with an IP of 0 stops unwinding process.


example:

void (*fp)() = NULL;

fp();


The testcase is both clang and g++ friendly. You can see from the output of the posted testcase that backtrace does this job.

Can we somehow force libunwind (unw_step) to ignore NULL IP and keep unwinding?

Here is the testcase:


#define UNW_LOCAL_ONLY

#include <libunwind.h>

#include <iostream>

#include <signal.h>

#include <execinfo.h>

#include <cassert>

void gen_segv_bad_ip(){

printf("\nInside gen_segv_bad_ip --> %p", gen_segv_bad_ip); fflush(stdout);

int (*fp)(int) = (int (*)(int)) NULL;

//Bad IP!!!

int g = fp(100);

}


void bail(){

printf("\nInside bail --> %p", bail); fflush(stdout);

gen_segv_bad_ip();

}


void foo3(){ printf("\nInside foo3 --> %p", foo3); fflush(stdout); bail(); }

void foo2(){ printf("\nInside foo2 --> %p", foo2); fflush(stdout); foo3(); }

void foo1(){ printf("\nInside foo1 --> %p", foo1); fflush(stdout); foo2(); }

void foo(){ printf("\nInside foo --> %p", foo); fflush(stdout); foo1(); }


/* Modified example given by libunwind */

void show_backtrace (unw_cursor_t *cursor) {

printf("\n\nInside show_backtrace --> %p\n", show_backtrace);

fflush(stdout);



unw_word_t ip, sp;

char buf[1000];

size_t len = sizeof(buf);

unw_word_t off;

do {

unw_get_reg(cursor, UNW_REG_IP, &ip);

unw_get_reg(cursor, UNW_REG_SP, &sp);

printf("ip = %llX sp = %llX ",ip, sp);

buf[0] = '\0';

unw_get_proc_name(cursor, buf, len, &off);

std::cout << "Procedure name returned --> " << buf << std::endl;

} while (unw_step(cursor) > 0);

printf("Leaving show_backtrace\n");

}



void segv_helper(void *uc){

printf("\nInside segv_helper --> %p\n", segv_helper);

fflush(stdout);


unw_cursor_t cursor;

unw_word_t ip, sp;

std::cout << "Getting local context " << std::endl;

int a = unw_getcontext((unw_context_t*) uc);

std::cout << "unw_init_local returned " << unw_init_local(&cursor, (unw_context_t*) uc) << std::endl;


unw_get_reg(&cursor, UNW_REG_IP, &ip);

unw_get_reg(&cursor, UNW_REG_SP, &sp);

printf("IP = %llX SP = %llX", ip, sp);

fflush(stdout);

show_backtrace(&cursor);


printf("Leaving segv_helper\n");

fflush(stdout);

}



void segv_handler (int signum, siginfo_t* info, void *old_context){

//Show stacktrace using backtrace....

void *buff[300];

int size = 300, nptrs;

char **pbuff;

nptrs = backtrace((void**) &buff, size);

printf("\n\nbacktrace() returned %d addresses\n", nptrs);

assert(NULL != (pbuff = backtrace_symbols(buff, nptrs)));

for (int i = 0; i < nptrs; i++) {

printf ("%s\n", pbuff[i]);

fflush(stdout);

}

free(pbuff);


printf("\nInside segv_handler --> %p\n", segv_handler);

fflush(stdout);


segv_helper( old_context );


std::cout << "\n\nBAILING...\n";

exit(1);

}



void test_signal_handler(int signum){

std::cout << "\nInside test_signal_handler. I should not be here...\n";

signal(SIGSEGV, SIG_DFL);

}



int main()

{

//Install signal handler...

struct sigaction new_sigaction, old_sigaction;

new_sigaction.sa_sigaction = segv_handler;

new_sigaction.sa_flags = SA_SIGINFO;

sigemptyset (&new_sigaction.sa_mask);

sigaddset(&new_sigaction.sa_mask, SIGSEGV);

sigaction (SIGSEGV, NULL, &new_sigaction);

if (old_sigaction.sa_handler != SIG_IGN){

new_sigaction.sa_handler = test_signal_handler;

new_sigaction.sa_sigaction = segv_handler;

sigaction (SIGSEGV, &new_sigaction, &old_sigaction);

}


printf("\nInside main --> %p", main);

foo();


return 0;

}

OS X Mountain Lion (10.8)

Posted on Aug 29, 2012 2:13 PM

Reply
1 reply

Aug 29, 2012 2:19 PM in response to verpra

Sorry I didn't post the output before. Here it is:


Inside main --> 0x10e50a720

Inside foo --> 0x10e50a030

Inside foo1 --> 0x10e509fe0

Inside foo2 --> 0x10e509f90

Inside foo3 --> 0x10e509f40

Inside bail --> 0x10e509ef0

Inside gen_segv_bad_ip --> 0x10e509e90



backtrace() returned 10 addresses

0 unwind_nullip 0x000000010e50a509 _Z12segv_handleriP9__siginfoPv + 105

1 libsystem_c.dylib 0x00007fff94c87cfa _sigtramp + 26

2 ??? 0x00007fff6e140062 0x0 + 140735040192610

3 unwind_nullip 0x000000010e509f2f _Z4bailv + 63

4 unwind_nullip 0x000000010e509f7f _Z4foo3v + 63

5 unwind_nullip 0x000000010e509fcf _Z4foo2v + 63

6 unwind_nullip 0x000000010e50a01f _Z4foo1v + 63

7 unwind_nullip 0x000000010e50a06f _Z3foov + 63

8 unwind_nullip 0x000000010e50a7f4 main + 212

9 unwind_nullip 0x000000010e509e84 start + 52



Inside segv_handler --> 0x10e50a4a0



Inside segv_helper --> 0x10e50a270

Getting local context

unw_init_local returned 0

IP = 10E50A394 SP = 7FFF6E107470



Inside show_backtrace --> 0x10e50a080

ip = 10E50A394 sp = 7FFF6E107470 Procedure name returned --> _Z11segv_helperPv

ip = 10E50A696 sp = 7FFF6E1079A0 Procedure name returned --> _Z12segv_handleriP9__siginfoPv

ip = 7FFF94C87CFA sp = 7FFF6E1083C0 Procedure name returned --> _sigtramp

Leaving show_backtrace

Leaving segv_helper





BAILING...

libunwind while unwinding a NULL IP

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple ID.