📄 ntoacc.c
字号:
start = name;
// name = CollectNid( name, strlen( name ), nid );
for( ;; ) {
ch = *name;
if( ch != ' ' && ch != '\t' ) break;
++name;
}
if( name_ret != NULL ) {
*name_ret = name;
}
pid = 0;
for( ;; ) {
if( *name < '0' || *name > '9' ) break;
pid = (pid * 10) + (*name - '0');
++name;
}
if( *name != '\0') {
return( 0 );
}
return( pid );
}
static int nto_breakpoint( addr_off addr, int type, int size )
{
procfs_break brk;
brk.type = type;
brk.addr = addr;
brk.size = size;
if( devctl( ProcInfo.procfd, DCMD_PROC_BREAK, &brk, sizeof( brk ), 0 ) != EOK ) {
dbg_print(( "failed to manipulate breakpoint!\n" ));
return( 1 );
}
else {
return( 0 );
}
}
static bool setup_rdebug( void )
{
if( GetLdInfo( ProcInfo.procfd, ProcInfo.dynsec_va, &ProcInfo.rdebug_va, &ProcInfo.ld_bp_va ) ) {
struct r_debug rdebug;
dbg_print(( "rdebug at %08x, ld breakpoint at %08x\n",
(unsigned)ProcInfo.rdebug_va, (unsigned)ProcInfo.ld_bp_va ));
ReadMem( ProcInfo.procfd, &rdebug, ProcInfo.rdebug_va, sizeof( rdebug ) );
AddLibs( ProcInfo.procfd, (addr_off)rdebug.r_map );
ProcInfo.have_rdebug = TRUE;
/* Set a breakpoint in dynamic linker. That way we can be
* informed on dynamic library load/unload events.
*/
dbg_print(( "Setting ld breakpoint at %08x\n", (unsigned)ProcInfo.ld_bp_va ));
nto_breakpoint( ProcInfo.ld_bp_va, _DEBUG_BREAK_EXEC, 0 );
return( TRUE );
}
return( FALSE );
}
/* Translate pid to the corresponding executable's pathname. */
static size_t pid_to_name( pid_t pid, char *exe_name, size_t len )
{
int procfd;
char buf[PATH_MAX];
procfs_debuginfo *dbg_info;
*exe_name = '\0';
snprintf( buf, sizeof( buf ) - 1, "%s/%d/as", ProcInfo.procfs_path, pid );
procfd = open( buf, O_RDONLY );
if( procfd != -1 ) {
dbg_info = (procfs_debuginfo *)buf;
dbg_info->path[0] = '\0';
if( devctl( procfd, DCMD_PROC_MAPDEBUG_BASE, dbg_info, sizeof( buf ), 0 ) == EOK ) {
if( strncmp( dbg_info->path, "./", 2 ) && (*dbg_info->path != '/') ) {
// Bug in QNX? Initial '/' seems to be missing sometimes.
strcpy( exe_name, "/" );
}
strncat( exe_name, dbg_info->path, len - 16 );
}
close( procfd );
}
return( strlen( exe_name ) + 1 );
}
unsigned ReqProg_load( void )
{
char **args;
char *parms;
char *parm_start;
int i;
char exe_name[PATH_MAX];
char *name;
pid_t save_pgrp;
sigset_t sig_set;
prog_load_req *acc;
prog_load_ret *ret;
unsigned len;
int fds[3];
struct inheritance inherit;
acc = GetInPtr( 0 );
ret = GetOutPtr( 0 );
ProcInfo.sig = -1;
ProcInfo.tid = -1;
ProcInfo.at_end = FALSE;
ProcInfo.fork = FALSE;
ProcInfo.have_rdebug = FALSE;
ProcInfo.rdebug_va = 0;
ProcInfo.dynsec_va = 0;
parms = (char *)GetInPtr( sizeof( *acc ) );
parm_start = parms;
len = GetTotalSize() - sizeof( *acc );
if( acc->true_argv ) {
i = 1;
for( ;; ) {
if( len == 0 ) break;
if( *parms == '\0' ) {
i++;
}
++parms;
--len;
}
args = alloca( i * sizeof( *args ) );
parms = parm_start;
len = GetTotalSize() - sizeof( *acc );
i = 1;
for( ;; ) {
if( len == 0 ) break;
if( *parms == '\0' ) {
args[ i++ ] = parms + 1;
}
++parms;
--len;
}
args[i - 1] = NULL;
} else {
while( *parms != '\0' ) {
++parms;
--len;
}
++parms;
--len;
i = SplitParms( parms, NULL, len );
args = alloca( (i + 2) * sizeof( *args ) );
args[ SplitParms( parms, &args[1], len ) + 1 ] = NULL;
}
args[0] = parm_start;
ProcInfo.pid = RunningProc( args[0], &name );
if( ProcInfo.pid != 0 ) {
ProcInfo.loaded_proc = FALSE;
} else {
args[0] = name;
if( FindFilePath( TRUE, args[0], exe_name ) == 0 ) {
exe_name[0] = '\0';
}
save_pgrp = getpgrp();
setpgid( 0, OrigPGrp );
/* Clear pending SIGUSR1 signals but don't change behaviour */
signal( SIGUSR1, signal( SIGUSR1, SIG_IGN ) );
sigemptyset( &sig_set );
sigaddset( &sig_set, SIGUSR1 );
sigprocmask( SIG_UNBLOCK, &sig_set, NULL );
memset( &inherit, 0, sizeof( inherit ) );
if( ND_NODE_CMP( ProcInfo.node, ND_LOCAL_NODE ) != 0 ) {
inherit.nd = nto_node();
inherit.flags |= SPAWN_SETND;
inherit.flags &= ~SPAWN_EXEC;
}
inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD;
inherit.pgroup = SPAWN_NEWPGROUP;
/* Only inherit standard handles; don't let child inherit everything. */
fds[0] = STDIN_FILENO;
fds[1] = STDOUT_FILENO;
fds[2] = STDERR_FILENO;
dbg_print(( "attempting to spawn '%s'", exe_name ));
ProcInfo.pid = spawnp( exe_name, 3, fds, &inherit, args,
!ND_NODE_CMP( ProcInfo.node, ND_LOCAL_NODE) ? dbg_environ : NULL );
/* Block SIGUSR1 again */
sigprocmask( SIG_BLOCK, &sig_set, NULL );
dbg_print(( ": received pid %d\n", ProcInfo.pid ));
setpgid( 0, save_pgrp );
ProcInfo.loaded_proc = TRUE;
}
ret->flags = 0;
if( ProcInfo.pid != -1 ) {
// Tell debugger to ignore segment values when comparing pointers
ret->flags |= LD_FLAG_IS_32 | LD_FLAG_IGNORE_SEGMENTS;
ProcInfo.pid = proc_attach( ProcInfo.pid, &ProcInfo.procfd, &ProcInfo.tid );
if( ProcInfo.pid == 0 ) {
if( ProcInfo.loaded_proc ) {
SignalKill( nto_node(), ProcInfo.pid, 0, SIGKILL, 0, 0 );
}
goto fail;
}
if( !ProcInfo.loaded_proc ) {
pid_to_name( ProcInfo.pid, exe_name, sizeof( exe_name ) );
dbg_print(( "attached to '%s'\n", exe_name ));
ret->flags |= LD_FLAG_IS_STARTED;
}
ret->task_id = ProcInfo.pid;
ProcInfo.dynsec_va = GetDynSection( exe_name );
AddProcess( exe_name, ProcInfo.dynsec_va );
if( ProcInfo.dynsec_va ) {
setup_rdebug();
}
errno = 0;
}
fail:
ret->err = errno;
if( ret->err != 0 ) {
proc_detach( NULL );
}
// It might be better to use handle 1 for the debuggee
ret->mod_handle = 0;
CONV_LE_32( ret->err );
CONV_LE_32( ret->task_id );
CONV_LE_32( ret->mod_handle );
return( sizeof( *ret ) );
}
unsigned ReqProg_kill( void )
{
prog_kill_ret *ret;
ret = GetOutPtr( 0 );
dbg_print(( "killing current process (pid %d)\n", ProcInfo.pid ));
if( ProcInfo.pid ) {
if( ProcInfo.loaded_proc && !ProcInfo.at_end ) {
SignalKill( nto_node(), ProcInfo.pid, 0, SIGKILL, 0, 0 );
}
proc_detach( NULL );
}
ProcInfo.sig = -1;
ProcInfo.at_end = FALSE;
ProcInfo.save_in = -1;
ProcInfo.save_out = -1;
ret->err = 0;
CONV_LE_32( ret->err );
return( sizeof( *ret ) );
}
unsigned ReqSet_break( void )
{
set_break_req *acc;
set_break_ret *ret;
acc = GetInPtr( 0 );
CONV_LE_32( acc->break_addr.offset );
CONV_LE_16( acc->break_addr.segment );
ret = GetOutPtr( 0 );
dbg_print(( "setting breakpoint at %04x:%08x\n", acc->break_addr.segment,
(unsigned)acc->break_addr.offset ));
nto_breakpoint( acc->break_addr.offset, _DEBUG_BREAK_EXEC, 0 );
return( sizeof( *ret ) );
}
unsigned ReqClear_break( void )
{
clear_break_req *acc;
acc = GetInPtr( 0 );
CONV_LE_32( acc->break_addr.offset );
CONV_LE_16( acc->break_addr.segment );
dbg_print(( "clearing breakpoint at %04x:%08x\n", acc->break_addr.segment,
(unsigned)acc->break_addr.offset ));
nto_breakpoint( acc->break_addr.offset, _DEBUG_BREAK_EXEC, -1 );
return( 0 );
}
static int nto_watchpoint( int addr, int len, int type )
{
procfs_break brk;
switch( type ) {
case 1: /* Read */
brk.type = _DEBUG_BREAK_RD;
break;
case 2: /* Read/Write */
brk.type = _DEBUG_BREAK_RW;
break;
default: /* Modify */
/* FIXME: brk.type = _DEBUG_BREAK_RWM gives EINVAL for some reason. */
brk.type = _DEBUG_BREAK_RW;
}
brk.type |= _DEBUG_BREAK_HW; /* Always ask for HW watchpoint */
brk.addr = addr;
brk.size = len;
if( devctl( ProcInfo.procfd, DCMD_PROC_BREAK, &brk, sizeof( brk ), 0 ) != EOK ) {
dbg_print(( "Failed to manipulate hardware watchpoint\n" ));
return( -1 );
}
return( 0 );
}
unsigned ReqSet_watch( void )
{
set_watch_req *acc;
set_watch_ret *ret;
acc = GetInPtr( 0 );
CONV_LE_32( acc->break_addr.offset );
CONV_LE_16( acc->break_addr.segment );
ret = GetOutPtr( 0 );
ret->multiplier = 1000;
ret->err = 1;
dbg_print(( "setting watchpoint %d bytes at %04x:%08x\n", acc->size,
acc->watch_addr.segment, (unsigned)acc->watch_addr.offset ));
if( nto_watchpoint( acc->watch_addr.offset, acc->size, 1 ) == 0 ) {
/* Succeeded */
ret->err = 0;
ret->multiplier |= USING_DEBUG_REG;
}
CONV_LE_32( ret->err );
CONV_LE_32( ret->multiplier );
return( sizeof( *ret ) );
}
unsigned ReqClear_watch( void )
{
clear_watch_req *acc;
acc = GetInPtr( 0 );
CONV_LE_32( acc->watch_addr.offset );
CONV_LE_16( acc->watch_addr.segment );
dbg_print(( "clearing watchkpoint at %04x:%08x\n", acc->watch_addr.segment,
(unsigned)acc->watch_addr.offset ));
nto_watchpoint( acc->watch_addr.offset, -1, 1 );
return( 0 );
}
/* Run if user hit Ctrl-C twice */
static void KillRunHandler( int sig )
{
signal( sig, KillRunHandler );
dbg_print(( "sending SIGKILL to debuggee (pid %d)\n", ProcInfo.pid ));
/* Be brutal */
SignalKill( nto_node(), ProcInfo.pid, 0, SIGKILL, 0, 0 );
}
/* Run if user hit Ctrl-C once */
static void RunHandler( int sig )
{
/* If this doesn't work, try more severe methods */
signal( sig, KillRunHandler );
dbg_print(( "sending SIGINT to debuggee (pid %d)\n", ProcInfo.pid ));
SignalKill( nto_node(), ProcInfo.pid, 0, SIGINT, 0, 0 );
}
static void Resume( int step )
{
// TODO: set current thread here?
ProcInfo.run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE | _DEBUG_RUN_ARM;
if( step ) {
ProcInfo.run.flags |= _DEBUG_RUN_STEP;
}
sigemptyset( (sigset_t *)&ProcInfo.run.fault );
sigaddset( (sigset_t *)&ProcInfo.run.fault, FLTBPT );
sigaddset( (sigset_t *)&ProcInfo.run.fault, FLTTRACE );
sigaddset( (sigset_t *)&ProcInfo.run.fault, FLTILL );
sigaddset( (sigset_t *)&ProcInfo.run.fault, FLTPRIV );
sigaddset( (sigset_t *)&ProcInfo.run.fault, FLTBOUNDS );
sigaddset( (sigset_t *)&ProcInfo.run.fault, FLTIOVF );
sigaddset( (sigset_t *)&ProcInfo.run.fault, FLTIZDIV );
sigaddset( (sigset_t *)&ProcInfo.run.fault, FLTFPE );
sigaddset( (sigset_t *)&ProcInfo.run.fault, FLTPAGE );
// TODO: figure out which signals we should really stop on
sigemptyset( &ProcInfo.run.trace );
#if 1
sigaddset( (sigset_t *)&ProcInfo.run.trace, SIGINT );
sigaddset( (sigset_t *)&ProcInfo.run.trace, SIGQUIT );
sigaddset( (sigset_t *)&ProcInfo.run.trace, SIGTRAP );
sigaddset( (sigset_t *)&ProcInfo.run.trace, SIGFPE );
sigaddset( (sigset_t *)&ProcInfo.run.trace, SIGSEGV );
sigaddset( (sigset_t *)&ProcInfo.run.trace, SIGSTOP );
sigaddset( (sigset_t *)&ProcInfo.run.trace, SIGCHLD );
#endif
// sigfillset( &ProcInfo.run.trace );
ProcInfo.run.flags |= _DEBUG_RUN_CLRSIG | _DEBUG_RUN_CLRFLT;
if( devctl( ProcInfo.procfd, DCMD_PROC_RUN, &ProcInfo.run, sizeof( ProcInfo.run ), 0 ) != EOK ) {
dbg_print(( "failed to run debuggee!\n" ));
}
}
static int RunIt( unsigned step )
{
void (*old)();
int ret;
sigset_t sig_set;
siginfo_t info;
procfs_status status;
ret = 0;
Resume( step );
sigemptyset( &sig_set );
sigaddset( &sig_set, SIGUSR1 );
devctl( ProcInfo.procfd, DCMD_PROC_STATUS, &status, sizeof( status ), 0 );
while( !(status.flags & _DEBUG_FLAG_ISTOP) ) {
dbg_print(( "nothing interesting yet: flags = %x\n", status.flags) );
old = signal( SIGINT, RunHandler );
sigwaitinfo( &sig_set, &info );
signal( SIGINT, old );
devctl( ProcInfo.procfd, DCMD_PROC_STATUS, &status, sizeof( status ), 0 );
}
dbg_print(( "interesting: flags = %x, why = %x, tid=%d\n", status.flags, status.why, status.tid ));
/* It is unclear how to detect that thread state changed (threads added, deleted, etc.).
* We'll just report thread change every time we stop, unless we're single stepping.
*/
if( (status.tid != ProcInfo.tid) || !(status.flags & _DEBUG_FLAG_SSTEP) ) {
// If current tid is zero, the process ended. We're not interested.
if( status.tid ) {
ProcInfo.tid = status.tid;
ret |= COND_THREAD | COND_THREAD_EXTRA;
}
}
if( status.flags & _DEBUG_FLAG_SSTEP ) {
ret |= COND_TRACE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -