Hi. I try to unwind stack of a remote process when it is stopped on a
syscall.
And I have a problem. I'll explain it on syscall write. I have two examples:
one of this calls printf function and another calls write function. And when
syscall write happend in printf I got relevant call stack:
00000000b809c424 (sp=00000000bfb48400)
00000000b7fb34bf new_do_write+0x4f (sp=00000000bfb48440)
00000000b7fb37d6 _IO_do_write+0x26 (sp=00000000bfb4846c)
00000000b7fb42dd _IO_file_overflow+0xed (sp=00000000bfb4847c)
00000000b7fb6aaa __overflow+0x4a (sp=00000000bfb484a0)
00000000b7faa46b _IO_puts+0x16b (sp=00000000bfb484b8)
00000000080483b6 f+0x12 (sp=00000000bfb484e0)
00000000080483c3 g+0xb (sp=00000000bfb48500)
00000000080483d0 main+0xb (sp=00000000bfb48510)
00000000b7f62b86 __libc_start_main+0xe6 (sp=00000000bfb48520)
0000000008048311 _start+0x21 (sp=00000000bfb485a0)
but when it happend in wirte function I get call stack which contained only
main function:
00000000b804e424 +0xbfef0f18 (sp=00000000bf87281c)
0000000008048504 main+0xb (sp=00000000bf872860)
00000000b7f14b86 __libc_start_main+0xe6 (sp=00000000bf872870)
00000000080483e1 _start+0x21 (sp=00000000bf8728f0)
P.S.
Function which I use for unwinding:
void do_backtrace(pid_t target_pid)
{
unw_word_t ip, sp, start_ip = 0, off;
int n = 0, ret;
unw_proc_info_t pi;
unw_cursor_t c;
char buf[512];
size_t len;
fprintf(stderr, "Target pid is %lu\n", (unsigned long)target_pid);
as = unw_create_addr_space (&_UPT_accessors, 0);
if (!as)
panic ("unw_create_addr_space() failed");
ui = _UPT_create (target_pid);
ret = unw_init_remote (&c, as, ui);
if (ret < 0)
panic ("unw_init_remote() failed: ret=%d\n", ret);
do
{
if ((ret = unw_get_reg (&c, UNW_REG_IP, &ip)) < 0
|| (ret = unw_get_reg (&c, UNW_REG_SP, &sp)) < 0)
panic ("unw_get_reg/unw_get_proc_name() failed: ret=%d\n", ret);
if (n == 0)
start_ip = ip;
buf[0] = '\0';
if (print_names)
unw_get_proc_name (&c, buf, sizeof (buf), &off);
if (off)
{
len = strlen (buf);
if (len >= sizeof (buf) - 32)
len = sizeof (buf) - 32;
sprintf (buf + len, "+0x%lx", (unsigned long)off);
}
printf ("%016lx %-32s (sp=%016lx)\n", (long) ip, buf, (long) sp);
if ((ret = unw_get_proc_info (&c, &pi)) < 0)
panic ("unw_get_proc_info(ip=0x%lx) failed: ret=%d\n", (long) ip,
ret);
else printf ("\tproc=%016lx-%016lx\n\thandler=%lx lsda=%lx\n",
(long) pi.start_ip, (long) pi.end_ip,
(long) pi.handler, (long) pi.lsda);
#if UNW_TARGET_IA64
{
unw_word_t bsp;
if ((ret = unw_get_reg (&c, UNW_IA64_BSP, &bsp)) < 0)
panic ("unw_get_reg() failed: ret=%d\n", ret);
else printf (" bsp=%lx", bsp);
}
#endif
ret = unw_step (&c);
if (ret < 0)
{
unw_get_reg (&c, UNW_REG_IP, &ip);
panic ("FAILURE: unw_step() returned %d for ip=%lx (start
ip=%lx)\n",
ret, (long) ip, (long) start_ip);
}
if (++n > 64)
{
/* guard against bad unwind info in old libraries... */
panic ("too deeply nested---assuming bogus unwind (start
ip=%lx)\n",
(long) start_ip);
break;
}
}
while (ret > 0);
if (ret < 0)
panic ("unwind failed with ret=%d\n", ret);
printf ("\n\n================\n\n");
_UPT_destroy (ui);
}
Test example which uses printf:
#include <stdio.h>
void f(void){
printf("Hello libunwind\n");
}
void g(void){
f();
}
int main(){
g();
}
Test example which uses write:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
void func(){
int pipe;
char* buffer;
if( NULL == ( buffer = (char*)malloc( sizeof(char)*5 ) ) )
perror("Malloc fail with ");
buffer[0] = 'a';
if (-1 == (pipe = open("./test.txt", O_WRONLY, 0))){
perror("Can't open file ");
}
write( pipe, buffer, 5 );
close(pipe);
}
int main(int argc, char *argv[]) {
func();
}
Program which I use to test do_backtrace():
int main(int argc, char* argv[])
{ pid_t child;
char *str;
long orig_eax, eax;
long params[3];
int status;
int insyscall = 0;
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl(argv[1], argv[1], NULL);
}
else {
while(1) {
wait(&status);
if(WIFEXITED(status))
break;
orig_eax = ptrace(PTRACE_PEEKUSER,
child, 4 * ORIG_EAX, NULL);
if(orig_eax == SYS_write) {
if(insyscall == 0) {
/* Syscall entry */
insyscall = 1;
printf("Syscall write entry\n");
}
else {
/* Syscall exit */
eax = ptrace(PTRACE_PEEKUSER,
child, 4 * EAX, NULL);
printf("Write returned with %ld\n", eax);
insyscall = 0;
}
}
do_backtrace(child);
ptrace(PTRACE_SYSCALL,
child, NULL, NULL);
}
}
return 0;
}
Thanks in advance.
Tatiana
_______________________________________________
Libunwind-devel mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/libunwind-devel