当前位置:早雪网网络学院编程文档C/C++ → Unix编程/应用问答中文版 ---2.堆栈相关问题

Unix编程/应用问答中文版 ---2.堆栈相关问题

减小字体 增大字体 作者:不详  来源:supcode.com收集整理  发布时间:2005-7-22 19:40:33
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)的最后

[1] [2] [3] [4]  下一页


Tags:Unix,编程,应用,问答,中文版,堆栈,相关,问题
[数据载入中...] [返回上一页] [打 印]