⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unix编程应用问答中文版.txt

📁 这份文档不是FAQ(Frequently Answered Question)
💻 TXT
📖 第 1 页 / 共 5 页
字号:

/*
 * 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" );
}

/* ......................................................................... */

Q: 我正在使用Solaris系统,"uname -a"显示如下

   SunOS usunnad01 5.8 Generic_108528-14 sun4u sparc SUNW,UltraAX-i2

   假设有如下代码

    caller_func ()
    {
        called_func();
    }

    called_func ()
    {
        printf( "called_func() is being called from %s\n", some_magic_func() );
    }

    我期待着这样的执行输出

    "called_func() is being called from caller_func()"

    请问如何实现some_magic_func(),C或者汇编语言编程都可以。

D: Paul Pluzhnikov <ppluzhnikov@earthlink.net>

看看mpatrol的源代码,其中有traceback()函数可以给出整个调用栈回溯,而不仅仅
是主调函数。

D: Peter Ammon <pa44@cornell.edu>

可以考虑使用宏,这是一个例子

--------------------------------------------------------------------------
/*
 * gcc -Wall -pipe -g -o test test.c
 */
#include <stdio.h>

#define CALL(x) (printf("Calling %s from %s\n", #x, __FUNCTION__), x)

int main ( void )
{
    char buf[64];

    while ( CALL( fgets( buf, sizeof( buff ), stdin ) ) != NULL )
    {
        CALL( puts( buf ) );
    }
    return( 0 );
}
--------------------------------------------------------------------------

A: Sun Microsystems 2000-06-13

下面演示如何编程获取当前运行中线程调用栈回溯。惟一要做的就是在应用程序中调
用csprintstack(),记得链接库选项-ldl。

--------------------------------------------------------------------------
/*
 * For SPARC/Solaris 8
 * gcc -D__sparc -Wall -pipe -g -o test test.c -ldl
 *
 * For x86/Solaris 9
 * gcc -D__i386 -Wall -pipe -g -o test test.c -ldl
 */
#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
#include <dlfcn.h>
#include <setjmp.h>
#include <sys/frame.h>
#include <sys/procfs_isa.h>

#if defined(sparc) || defined(__sparc)
#define FRAME_PTR_REGISTER REG_SP
#endif

#if defined(i386) || defined(__i386)
#define FRAME_PTR_REGISTER EBP
#endif

struct frame * csgetframeptr ( void )
{
    ucontext_t u;

    ( void )getcontext( &u );
    return( ( struct frame * )( ( struct frame * )u.uc_mcontext.gregs[FRAME_PTR_REGISTER] )->fr_savfp );
}  /* end of csgetframeptr */

void cswalkstack ( struct frame *fp, int ( *operate_func ) ( void *, void * ), void *usrarg )
{
    void *savpc;

    while ( fp && ( savpc = ( void * )fp->fr_savpc )
            && ( *operate_func )( savpc, usrarg ) == 0 )
    {
        fp = ( void * )fp->fr_savfp;
    }
}  /* end of cswalkstack */

static int csprintaddress ( void *pc, void *usrarg )
{
    Dl_info  info;
    char    *func;
    char    *lib;

    if ( dladdr( pc, &info ) == 0 )
    {
        func = "??";
        lib  = "??";
    }
    else
    {
        lib  = ( char * )info.dli_fname;
        func = ( char * )info.dli_sname;
    }
    fprintf( ( FILE * )usrarg, "%s:%s+0x%x\n", lib, func,
             ( unsigned int )pc - ( unsigned int )info.dli_saddr );
    return( 0 );
}  /* end of csprintaddress */

void csprintstack ( FILE *f )
{
    cswalkstack( csgetframeptr(), csprintaddress, ( void * )f );
}  /* end of csprintstack */

void call_2 ( void )
{
    csprintstack( stderr );
}  /* end of call_2 */

void call_1 ( void )
{
    call_2();
}  /* end of call_1 */

void call_0 ( void )
{
    call_1();
}  /* end of call_0 */

int main ( void )
{
    call_0();
    return( EXIT_SUCCESS );
}  /* end of main */
--------------------------------------------------------------------------

[scz@ /export/home/scz/src]> gcc -D__sparc -Wall -pipe -g -o test test.c -ldl
[scz@ /export/home/scz/src]> ./test
test:call_2+0xc
test:call_1+0x4
test:call_0+0x4
test:main+0x4
test:_start+0x5c
[scz@ /export/home/scz/src]>

[scz@ /export/home/scz/src]> gcc -D__i386 -Wall -pipe -g -o test test.c -ldl
[scz@ /export/home/scz/src]> ./test
/export/home/scz/src/test:call_2+0x13
/export/home/scz/src/test:call_1+0xb
/export/home/scz/src/test:call_0+0xb
/export/home/scz/src/test:main+0x15
/export/home/scz/src/test:_start+0x5d
[scz@ /export/home/scz/src]>

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/Solaris 8       栈底是0x08048000
x86/FreeBSD         栈底是0xbfc00000 (栈底往低地址的4个字节总是零)
x86/NetBSD 1.5      栈底是0xbfbfe000
x86/OpenBSD 2.8/3.0 栈底是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 -pipe -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 volatile sig_atomic_t  canjump = 0;
static Sigfunc               *seg_handler;
static Sigfunc               *bus_handler;  /* for xxxBSD */

Sigfunc * signal ( int signo, Sigfunc * func )
{
    struct sigaction act, oact;

    act.sa_handler = func;
    sigemptyset( &act.sa_mask );
    act.sa_flags   = 0;
    if ( sigaction( signo, &act, &oact ) < 0 )
    {
        return( SIG_ERR );
    }
    return( oact.sa_handler );
}  /* end of signal */

static Sigfunc * Signal ( int signo, Sigfunc * func )  /* for our signal() function */
{
    Sigfunc * sigfunc;

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

static char * get_stack_bottom ( void )
{
    volatile char *c;  /* for autovar, must be volatile */

    seg_handler = Signal( SIGSEGV, segfault );
    bus_handler = Signal( SIGBUS, segfault );
    c           = ( char * )&c;

    if ( sigsetjmp( jmpbuf, 1 ) != 0 )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -