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

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

减小字体 增大字体 作者:不详  来源:supcode.com收集整理  发布时间:2005-7-22 19:40:33
程序,用户空间上限是_userlimit,也就是0xffffffff80000000 

# /opt/SUNWspro/SC5.0/bin/cc -xarch=v9 -O -o gstack gstack.c 
# ./gstack 
Current stack bottom is at 0xffffffff80000000 


对于SPARC/Solaris 2.6 32-bit kernel mode 

# echo "_userlimit /X" | adb -k /dev/ksyms /dev/mem 
physmem 3d24 
_userlimit: 
_userlimit:     f0000000 


2.5 如何得到一个运行中进程的内存映像 

A: Sun Microsystems 1998-03-30 

有些时候必须得到一个运行中进程的内存映像而不能停止该进程,Solaris系统了这 
样的工具,gcore为运行中进程创建一个core文件。假设我的bash进程号是5347 

# gcore 5347 
gcore: core.5347 dumped 
# file core.5347 
core.5347:      ELF 32-位 MSB core文件 SPARC 版本 1,来自'bash' 


注意,只能获取属主是你自己的进程的内存映像,除非你是root。 

2.6 调试器如何工作的 

Q: 我想在一个自己编写的程序中单步运行另外一个程序,换句话说,那是一个调试 
   器,该如何做? 

A: Erik de Castro Lopo <nospam@mega-nerd.com> 

   这是一个操作系统相关的问题。最一般的回答是使用ptrace()系统调用,尽管我 
   不确认究竟这有多么普遍。Linux man手册上说SVr4、SVID EXT、AT&T、X/OPEN 
   和BSD 4.3都支持它。 

   为了使用ptrace(),你的程序应该调用fork(),然后在子进程中做如下调用: 

   ptrace( PTRACE_TRACEME, 0, 0, 0 ); 

   接下来调用exec()家族的函数执行你最终企图跟踪的程序。 

   为了单步进入子进程,在父进程中调用: 

   ptrace( PTRACE_SINGLESTEP, 0, 0, 0 ); 

   还有一些其他函数做恢复/设置寄存器、内存变量一类的工作。 

   GDB的源代码足以回答这个问题。 

2.7 x86/Linux上如何处理SIGFPE信号 

Q: 参看如下程序 

-------------------------------------------------------------------------- 
/* 
* gcc -Wall -pipe -O3 -o sigfpe_test_0 sigfpe_test_0.c 

* 注意与下面的编译效果进行对比,去掉优化开关-O3 

* gcc -Wall -pipe -o sigfpe_test_0 sigfpe_test_0.c 
*/ 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <signal.h> 
#include <unistd.h> 
#include <setjmp.h> 

/* 
* for signal handlers 
*/ 
typedef void Sigfunc ( int ); 

       Sigfunc * signal ( int signo, Sigfunc *func ); 
static Sigfunc * Signal ( int signo, Sigfunc *func ); 
static void      on_fpe ( int signo ); 

Sigfunc * signal ( int signo, Sigfunc *func ) 

    struct sigaction act, oact; 

    act.sa_handler = func; 
    sigemptyset( &act.sa_mask ); 
    act.sa_flags   = 0; 
    if ( signo == SIGALRM ) 
    { 
#ifdef  SA_INTERRUPT 
        act.sa_flags |= SA_INTERRUPT;  /* SunOS 4.x */ 
#endif 
    } 
    else 
    { 
#ifdef  SA_RESTART 
        act.sa_flags |= SA_RESTART;  /* SVR4, 44BSD */ 
#endif 
    } 
    if ( sigaction( signo, &act, &oact ) < 0 ) 
    { 
        return( SIG_ERR ); 
    } 
    return( oact.sa_handler ); 
}  /* end of signal */ 

static Sigfunc * Signal ( int signo, Sigfunc *func ) 

    Sigfunc *sigfunc; 

    if ( ( sigfunc = signal( signo, func ) ) == SIG_ERR ) 
    { 
        perror( "signal" ); 
        exit( EXIT_FAILURE ); 
    } 
    return( sigfunc ); 
}  /* end of Signal */ 

static void on_fpe ( int signo ) 

    fprintf( stderr, "here is on_fpe\n" ); 
    return; 
}  /* end of on_fpe */ 

int main ( int argc, char * argv[] ) 

    unsigned int i; 

    Signal( SIGFPE, on_fpe ); 
    i = 51211314 / 0; 
    /* 
     * 另外,增加这行后,再次对比有-O3和无-O3的效果 
     * 
     * fprintf( stderr, "i = %#X\n", i ); 
     */ 
    return( EXIT_SUCCESS ); 
}  /* end of main */ 
-------------------------------------------------------------------------- 

有-O3、无-O3,以及有无最后那条fprintf()语句,效果上有差别,自行对比。如果 
输出"here is on_fpe",则会发现永不停止。 

D: 小四 <scz@nsfocus.com> 2001-12-14 18:25 

为了便于讨论,约定两个名词,中断和异常。这里中断指最常规的中断,比如int指 
令带来的软中断。异常的典型代表有除0错。区别在于,发生异常时,x86架构上CPU 
将当前EIP(指向引发异常的指令)压栈,发生中断时,x86架构上CPU将当前EIP的后一 
个地址(指向引发中断的指令的后一条指令)压栈。在异常处理代码中,如果认为能够 
从灾难中恢复,可以不修改被压栈的EIP,从而返回到引发异常的指令处。更多细节 
请查看Intel手册。 

这些是从前DOS下残留的汇编知识,不过也快忘光了,刚才又找元宝宝确认了一下。 

在上述代码中,on_fpe()直接返回了,导致再次触发异常,所以无休止输出。事实上 
在所有的计算器处理程序中,都会对SIGFPE信号做相应处理,前些日子看yacc/lex的 
时候又碰上过。正确的做法是,利用远跳转转移,让开引发异常的指令。 

代码修改如下 

-------------------------------------------------------------------------- 
/* 
* gcc -Wall -pipe -O3 -o sigfpe_test_1 sigfpe_test_1.c 

* 注意与下面的编译效果进行对比,去掉优化开关-O3 

* gcc -Wall -pipe -o sigfpe_test_1 sigfpe_test_1.c 
*/ 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <signal.h> 
#include <unistd.h> 
#include <setjmp.h> 

/* 
* for signal handlers 
*/ 
typedef void Sigfunc ( int ); 

       Sigfunc * signal ( int signo, Sigfunc *func ); 
static Sigfunc * Signal ( int signo, Sigfunc *func ); 
static void      on_fpe ( int signo ); 

static sigjmp_buf             jmpbuf; 
static volatile sig_atomic_t  canjump = 0; 

Sigfunc * signal ( int signo, Sigfunc *func ) 

    struct sigaction act, oact; 

    act.sa_handler = func; 
    sigemptyset( &act.sa_mask ); 
    act.sa_flags   = 0; 
    if ( signo == SIGALRM ) 
    { 
#ifdef  SA_INTERRUPT 
        act.sa_flags |= SA_INTERRUPT;  /* SunOS 4.x */ 
#endif 
    } 
    else 
    { 
#ifdef  SA_RESTART 
        act.sa_flags |= SA_RESTART;  /* SVR4, 44BSD */ 
#endif 
    } 
    if ( sigaction( signo, &act, &oact ) < 0 ) 
    { 
        return( SIG_ERR ); 
    } 
    return( oact.sa_handler ); 
}  /* end of signal */ 

static Sigfunc * Signal ( int signo, Sigfunc *func ) 

    Sigfunc *sigfunc; 

    if ( ( sigfunc = signal( signo, func ) ) == SIG_ERR ) 
    { 
        perror( "signal" ); 
        exit( EXIT_FAILURE ); 
    } 
    return( sigfunc ); 
}  /* end of Signal */ 

static void on_fpe ( int signo ) 

    if ( canjump == 0 ) 
    { 
        return;  /* unexpected signal, ignore */ 
    } 
    canjump = 0; 
    fprintf( stderr, "here is on_fpe\n" ); 
    siglongjmp( jmpbuf, signo );  /* jump back to main, don't return */ 
    return; 
}  /* end of on_fpe */ 

int main ( int argc, char * argv[] ) 

    unsigned int i; 

    if ( sigsetjmp( jmpbuf, 1 ) != 0 ) 
    { 
        fprintf( stderr

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

[数据载入中...] [返回上一页] [打 印]