EDU511 国际专业IT教育服务门户 |
|
|
Unix编程/应用问答中文版 ---2.堆栈相关问题日期:08-06-02 22:44:11 点击: 来源:中讯IT 2. 堆栈相关问题 2.1 如何理解pstack的输出信息 2.2 2.3 Solaris中如何获取一个C程序的调用栈回溯 2.4 如何编程获取栈底地址 2.5 如何得到一个运行中进程的内存映像 2.6 调试器如何工作的 2.7 x86/Linux上如何处理SIGFPE信号 -------------------------------------------------------------------------- 2. 堆栈相关问题 2.1 如何理解pstack的输出信息 Q: 080603a7 main (1, 80479b8, 80479c0) + d53 结尾的d53是什么 A: Roger A. Faulkner <raf@sunraf.Sun.COM> 在代码段绝对地址0x080603a7处,main()调用了一个函数,0x080603a7正是 main + 0xd53,换句话说,从main()函数开始的0xd53偏移处。 2.3 Solaris中如何获取一个C程序的调用栈回溯 Q: 我想在Solaris 2.6极其后续版本上获取一个C程序的调用栈回溯,类似如下输出 (10) 0x00045e08 integ + 0x408 [./two_brn.e] (11) 0x0006468c trajcem + 0x128 [./two_brn.e] (12) 0x00055490 fly_traj + 0xf58 [./two_brn.e] (13) 0x0004052c top_level + 0x14 [./two_brn.e] (14) 0x000567e4 _start + 0x34 [./two_brn.e] 这样我就可以知道当程序崩溃、死锁的时候代码执行到了何处。在HP-UX和IRIX上 可以利用U_STACK_TRACE()和trace_back_stack_and_print(),Solaris上呢? Q: 有没有办法显示当前堆栈中的数据(GNU/Linux系统)?我希望自己的异常处理程序 在进程结束前dump整个栈区(stack),以便观察到栈顶是什么函数。对于调试意想 不到的运行时错误而言,这很重要。 A: Bjorn Reese <breese@mail1.stofanet.dk> 用/usr/proc/bin/pstack [-F] <pid ...> 参看这个例子代码,http://home1.stofanet.dk/breese/debug/debug.tar.gz Q: is there a way to access call stack information at run time from within a program? i've been maintaining my own crude stack using __FUNCTION__ and linked lists but can't help but think there's gotta be a better way... A: Nate Eldredge <neldredge@hmc.edu> 这依赖于你的系统,如果使用glibc 2.1或更新版本,可以使用backtrace()函数, 参看<execinfo.h>,其他系统可能有不同的技术支持。 注意,你所使用的办法可能是唯一能够保证跨平台使用的 A: Andrew Gabriel <andrew@cucumber.demon.co.uk> Consultant Software Engineer 下面是一个backtrace()的应用举例,如果你使用Solaris 2.4及其后续版本,那 么这个例子可以很好的工作。很可能无法工作在64-bit模式下,我没有尝试过, 好像Solaris 7已经提供了一个类似的演示程序。还可以增加某些功能,我没有时 间了。 /* * Produce a stack trace for Solaris systems. * * Copyright (C) 1995-1998 Andrew Gabriel <andrew@cucumber.demon.co.uk> * Parts derived from Usenet postings of Bart Smaalders and Casper Dik. * */ /* ......................................................................... */ #include <setjmp.h> #include <sys/types.h> #include <sys/reg.h> #include <sys/frame.h> #include <dlfcn.h> #include <errno.h> #include <unistd.h> #include <stdio.h> #if defined(sparc) || defined(__sparc) #define FLUSHWIN() asm("ta 3"); #define FRAME_PTR_INDEX 1 #define SKIP_FRAMES 0 #endif #if defined(i386) || defined(__i386) #define FLUSHWIN() #define FRAME_PTR_INDEX 3 #define SKIP_FRAMES 1 #endif #if defined(ppc) || defined(__ppc) #define FLUSHWIN() #define FRAME_PTR_INDEX 0 #define SKIP_FRAMES 2 #endif /* ......................................................................... */ static void print_address ( void * pc ) { Dl_info info; if ( dladdr( pc, &info ) == 0 ) { /* not found */ fprintf( stderr, "*** %s:0x%x\n", "??", ( unsigned int )pc ); } else { /* found */ fprintf( stderr, "*** %s:%s+0x%x\n", info.dli_fname, info.dli_sname, ( unsigned int )pc - ( unsigned int )info.dli_saddr ); } return; } /* end of print_address */ /* ......................................................................... */ static int validaddr ( void * addr ) { static long pagemask = -1; char c; if ( pagemask == -1 ) { pagemask = ~( sysconf( _SC_PAGESIZE ) - 1 ); } addr = ( void * )( ( long )addr & pagemask ); if ( mincore( ( char * )addr, 1, &c ) == -1 && errno == ENOMEM ) { return 0; /* invalid */ } else { return 1; /* valid */ } } /* end of validaddr */ /* ......................................................................... */ /* * this function walks up call stack, calling print_addess * once for each stack frame, passing the pc as the argument. */ static void print_stack ( void ) { struct frame * sp; jmp_buf env; int i; int * iptr; FLUSHWIN(); setjmp( env ); iptr = ( int * )env; sp = ( struct frame * )iptr[ FRAME_PTR_INDEX ]; for ( i = 0; i < SKIP_FRAMES && sp; i++ ) { if ( !validaddr( sp ) || !validaddr( &sp->fr_savpc ) ) { fprintf( stderr, "***[stack pointer corrupt]\n" ); return; } sp = ( struct frame * )sp->fr_savfp; } i = 100; /* looping check */ while ( validaddr( sp ) && validaddr( &sp->fr_savpc ) && sp->fr_savpc && --i ) { print_address( ( void * )sp->fr_savpc ); sp = ( struct frame * )sp->fr_savfp; } } /* end of print_stack */ /* ......................................................................... */ void backtrace( void ) { fprintf( stderr, "***backtrace...\n" ); print_stack(); fprintf( stderr, "***backtrace ends\n" ); } /* ......................................................................... */ 2.4 如何编程获取栈底地址 Q: 虽然很多操作系统的用户进程栈底地址固定,但是我需要写一个可广泛移植C程序 获取这个栈底地址。 A: tt <warning3@nsfocus.com> 2001-06-02 19:40 假设堆栈(stack)向低地址方向增长,则所谓栈底指堆栈(stack)最高地址 x86/Linux 栈底是0xc0000000( 栈底往低地址的4个字节总是零 ) SPARC/Solaris 7/8 栈底是0xffbf0000( 栈底往低地址的4个字节总是零 ) SPARC/Solaris 2.6 栈底是0xf0000000( 栈底往低地址的4个字节总是零 ) x86/FreeBSD 栈底是0xbfc00000( 栈底往低地址的4个字节总是零 ) x86/NetBSD 1.5 栈底是0xbfbfe000 x86/OpenBSD 2.8 栈底是0xdfbfe000 D: jonah 对于NetBSD 1.5,栈底是0xbfc00000。根据源码,最高用户地址是0xbfbfe000,因为 最后4MB(2^22)的最后两页(0x2000字节,一页4096字节)保留用做U区,但是目前不再 使用这块内存。因此,0xbfbfe000才是真正的栈底。 tt在OpenBSD 2.8上测试结果,栈底是0xdfbfe000,注意和NetBSD 1.5相差很大。 A: tt <warning3@nsfocus.com> -------------------------------------------------------------------------- /* * gcc -Wall -O3 -o gstack gstack.c * * A simple example to get the current stack bottom address * warning3 <warning3@nsfocus.com> * 2001-06-01 * * Modified by scz <scz@nsfocus.com> * 2001-06-02 */ #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <setjmp.h> typedef void Sigfunc ( int ); /* for signal handlers */ Sigfunc * signal ( int signo, Sigfunc * func ); static Sigfunc * Signal ( int signo, Sigfunc * func ); static char * get_stack_bottom ( void ); static void segfault ( int signo ); static sigjmp_buf jmpbuf; static vol ( 责任编辑:) 前一篇: 后一篇: 相关新闻(文章)
|
登录模块加载中...
热点操作系统技术
|
| 友情链接 | |