📄 unix编程应用问答中文版.txt
字号:
/*
* 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 + -