📄 ntoacc.c
字号:
} else if( status.flags & _DEBUG_FLAG_TRACE_EXEC ) {
ret |= COND_BREAK;
} else if( status.flags & (_DEBUG_FLAG_TRACE_RD | _DEBUG_FLAG_TRACE_WR) ) {
ret |= COND_BREAK;
} else if( status.flags & _DEBUG_FLAG_ISTOP ) {
switch( status.why ) {
case _DEBUG_WHY_SIGNALLED:
case _DEBUG_WHY_FAULTED:
case _DEBUG_WHY_JOBCONTROL:
dbg_print(( "stopped on signal: %d\n", status.info.si_signo ));
if( status.info.si_signo == SIGINT ) {
ret |= COND_USER;
} else {
ProcInfo.sig = status.info.si_signo;
ret |= COND_EXCEPTION;
}
break;
case _DEBUG_WHY_TERMINATED: {
int wait_val = 0;
waitpid( ProcInfo.pid, &wait_val, WNOHANG );
dbg_print(( "debuggee terminated (pid %d), status collected (%d)\n",
ProcInfo.pid, wait_val ));
ProcInfo.at_end = TRUE;
ret |= COND_TERMINATE;
break;
}
case _DEBUG_WHY_REQUESTED:
/* We are assuming a requested stop is due to a SIGINT. */
ret |= COND_USER;
break;
}
}
/* Check the dynamic linker breakpoint. */
if( (ret & COND_BREAK) && (status.ip == ProcInfo.ld_bp_va) ) {
ret &= ~COND_BREAK;
ret |= COND_LIBRARIES;
ProcessLdBreakpoint( ProcInfo.procfd, ProcInfo.rdebug_va );
}
return( ret );
}
static unsigned ProgRun( bool step )
{
debug_greg_t regs;
prog_go_ret *ret;
int regsize;
ret = GetOutPtr( 0 );
memset( ret, 0, sizeof( *ret ) );
if( ProcInfo.at_end ) {
dbg_print(( "process terminated - nothing to do\n" ));
ret->conditions = COND_TERMINATE;
} else if( step ) {
dbg_print(( "about to step\n" ));
ret->conditions = RunIt( 1 );
} else {
dbg_print(( "about to run\n" ));
ret->conditions = RunIt( 0 );
}
if( !(ret->conditions & COND_TERMINATE) ) {
memset( ®s, 0, sizeof( regs ) );
devctl( ProcInfo.procfd, DCMD_PROC_GETGREG, ®s, sizeof( regs ), ®size );
ret->program_counter.offset = regs.x86.eip;
ret->program_counter.segment = regs.x86.cs;
ret->stack_pointer.offset = regs.x86.esp;
ret->stack_pointer.segment = regs.x86.ss;
/* If debuggee has dynamic section, try getting the r_debug struct
* every time the debuggee stops. The r_debug data may not be available
* immediately after the debuggee process loads.
*/
if( !ProcInfo.have_rdebug && ProcInfo.dynsec_va ) {
if( setup_rdebug() ) {
ret->conditions |= COND_LIBRARIES;
}
}
}
dbg_print(( "stopped at %04x:%08x because of %x\n", ret->program_counter.segment,
(unsigned)ret->program_counter.offset, ret->conditions ));
// Note: Some trap files always set COND_CONFIG here. This should only be
// necessary if we were switching between 32-bit and 16-bit code and the like.
// It should not be needed for QNX Neutrino.
CONV_LE_32( ret->stack_pointer.offset );
CONV_LE_16( ret->stack_pointer.segment );
CONV_LE_32( ret->program_counter.offset );
CONV_LE_16( ret->program_counter.segment );
CONV_LE_16( ret->conditions );
return( sizeof( *ret ) );
}
unsigned ReqProg_step( void )
{
return( ProgRun( TRUE ) );
}
unsigned ReqProg_go( void )
{
return( ProgRun( FALSE ) );
}
unsigned ReqRedirect_stdin( void )
{
redirect_stdin_ret *ret;
// TODO: implement if possible
ret = GetOutPtr( 0 );
ret->err = 1;
CONV_LE_32( ret->err );
return( sizeof( *ret ) );
}
unsigned ReqRedirect_stdout( void )
{
redirect_stdout_ret *ret;
// TODO: implement if possible
ret = GetOutPtr( 0 );
ret->err = 1;
CONV_LE_32( ret->err );
return( sizeof( *ret ) );
}
unsigned ReqFile_string_to_fullpath( void )
{
pid_t pid;
bool exe;
int len;
char *name;
char *fullname;
file_string_to_fullpath_req *acc;
file_string_to_fullpath_ret *ret;
/* -- convert string in acc->name to full path (searchpath style)
* in acc->info (MAXIMUM len acc->info_len).
*/
pid = 0;
acc = GetInPtr( 0 );
name = GetInPtr( sizeof( *acc ) );
ret = GetOutPtr( 0 );
fullname = GetOutPtr( sizeof( *ret ) );
exe = ( acc->file_type == TF_TYPE_EXE ) ? TRUE : FALSE;
if( exe ) {
pid = RunningProc( name, &name );
}
if( pid != 0 ) {
/* We aren't told how big the output buffer is! */
len = pid_to_name( pid, fullname, 512 );
dbg_print(( "pid %d -> name '%s'\n", pid, name ));
} else {
len = FindFilePath( exe, name, fullname );
}
if( len == 0 ) {
ret->err = ENOENT; /* File not found */
} else {
ret->err = 0;
}
CONV_LE_32( ret->err );
return( sizeof( *ret ) + len + 1 );
}
unsigned ReqGet_message_text( void )
{
static const char *const ExceptionMsgs[] = {
"",
TRP_QNX_hangup,
TRP_QNX_user_interrupt,
TRP_QNX_quit,
TRP_EXC_illegal_instruction,
TRP_QNX_trap,
//"I/O trap",
TRP_QNX_abort,
TRP_QNX_emt,
TRP_QNX_floating_point_error,
TRP_QNX_process_killed,
TRP_QNX_bus_error,
TRP_EXC_access_violation,
TRP_QNX_sys,
TRP_QNX_broken_pipe,
TRP_QNX_alarm,
TRP_QNX_process_termination,
TRP_QNX_user_signal_1,
TRP_QNX_user_signal_2,
TRP_QNX_child_stopped,
TRP_QNX_power_fail,
TRP_QNX_winch,
TRP_QNX_urgent,
TRP_QNX_poll,
TRP_QNX_process_stopped,
"",
TRP_QNX_process_continued,
TRP_QNX_device_ready,
"",
""
};
get_message_text_ret *ret;
char *err_txt;
ret = GetOutPtr( 0 );
err_txt = GetOutPtr( sizeof( *ret ) );
if( ProcInfo.fork ) {
ProcInfo.fork = FALSE;
strcpy( err_txt, TRP_QNX_PROC_FORK );
ret->flags = MSG_NEWLINE | MSG_WARNING;
} else {
if( ProcInfo.sig == -1 ) {
err_txt[0] = '\0';
} else if( ProcInfo.sig > ( (sizeof( ExceptionMsgs ) / sizeof( char * ) - 1) ) ) {
strcpy( err_txt, TRP_EXC_unknown );
} else {
strcpy( err_txt, ExceptionMsgs[ProcInfo.sig] );
}
ProcInfo.sig = -1;
ret->flags = MSG_NEWLINE | MSG_ERROR;
}
return( sizeof( *ret ) + strlen( err_txt ) + 1 );
}
unsigned ReqAddr_info( void )
{
addr_info_req *acc;
addr_info_ret *ret;
acc = GetInPtr( 0 );
ret = GetOutPtr( 0 );
ret->is_32 = TRUE;
return( sizeof( *ret ) );
}
unsigned ReqMachine_data( void )
{
machine_data_req *acc;
machine_data_ret *ret;
unsigned_8 *data;
acc = GetInPtr( 0 );
ret = GetOutPtr( 0 );
data = GetOutPtr( sizeof( *ret ) );
ret->cache_start = 0;
ret->cache_end = ~(addr_off)0;
*data = X86AC_BIG;
return( sizeof( *ret ) + sizeof( *data ) );
}
unsigned ReqThread_get_next( void )
{
thread_get_next_req *req;
thread_get_next_ret *ret;
procfs_status status;
req = GetInPtr( 0 );
CONV_LE_32( req->thread );
ret = GetOutPtr( 0 );
status.tid = req->thread + 1;
ret->state = 0;
if( ProcInfo.pid && !ProcInfo.at_end ) {
if( devctl( ProcInfo.procfd, DCMD_PROC_TIDSTATUS, &status, sizeof( status ), 0 ) != EOK ) {
dbg_print(( "failed to get thread status (tid %ld)\n", req->thread + 1 ));
ret->thread = 0;
} else {
ret->thread = status.tid;
ret->state = status.tid_flags & _NTO_TF_FROZEN ? THREAD_FROZEN : THREAD_THAWED;
}
} else {
/* If the debuggee isn't running, pretend there is one thread */
ret->thread = req->thread ? 0 : 1;
}
dbg_print(( "next thread %ld (in %ld), state %d\n", ret->thread, req->thread, ret->state ));
CONV_LE_32( ret->thread );
return( sizeof( *ret ) );
}
unsigned ReqThread_set( void )
{
thread_set_req *req;
thread_set_ret *ret;
pthread_t tid;
req = GetInPtr( 0 );
CONV_LE_32( req->thread );
ret = GetOutPtr( 0 );
tid = req->thread;
ret->err = 0;
ret->old_thread = ProcInfo.tid;
dbg_print(( "setting thread %d (currently %d)\n", tid, ProcInfo.tid ));
if( tid ) {
if( devctl( ProcInfo.procfd, DCMD_PROC_CURTHREAD, &tid, sizeof( tid ), 0 ) != EOK ) {
dbg_print(( "failed to set current thread to %d\n", tid ));
ret->err = EINVAL;
} else {
ProcInfo.tid = tid;
}
}
CONV_LE_32( ret->old_thread );
CONV_LE_32( ret->err );
return( sizeof( *ret ) );
}
unsigned ReqThread_freeze( void )
{
thread_freeze_req *req;
thread_freeze_ret *ret;
pthread_t tid;
req = GetInPtr( 0 );
CONV_LE_32( req->thread );
ret = GetOutPtr( 0 );
tid = req->thread;
ret->err = 0;
dbg_print(( "freezing thread %d\n", tid ));
if( tid ) {
/* If debuggee isn't running, do nothing but pretend it worked */
if( ProcInfo.pid && !ProcInfo.at_end ) {
if( devctl( ProcInfo.procfd, DCMD_PROC_FREEZETHREAD, &tid, sizeof( tid ), 0 ) != EOK ) {
dbg_print(( "failed to freeze thread %d\n", tid ));
ret->err = EINVAL;
}
}
} else {
ret->err = EINVAL;
}
CONV_LE_32( ret->err );
return( sizeof( *ret ) );
}
unsigned ReqThread_thaw( void )
{
thread_thaw_req *req;
thread_thaw_ret *ret;
pthread_t tid;
req = GetInPtr( 0 );
CONV_LE_32( req->thread );
ret = GetOutPtr( 0 );
tid = req->thread;
ret->err = 0;
dbg_print(( "thawing thread %d\n", tid ));
if( tid ) {
/* If debuggee isn't running, do nothing but pretend it worked */
if( ProcInfo.pid && !ProcInfo.at_end ) {
if( devctl( ProcInfo.procfd, DCMD_PROC_THAWTHREAD, &tid, sizeof( tid ), 0 ) != EOK ) {
dbg_print(( "failed to thaw thread %d\n", tid ));
ret->err = EINVAL;
}
}
} else {
ret->err = EINVAL;
}
CONV_LE_32( ret->err );
return( sizeof( *ret ) );
}
/* see <sys/state.h> */
static char *tstate_desc[STATE_MAX] = {
"DEAD",
"RUNNING",
"READY",
"STOPPED",
"SEND",
"RECEIVE",
"REPLY",
"STACK",
"WAITTHREAD",
"WAITPAGE",
"SIGSUSPEND",
"SIGWAITINFO",
"NANOSLEEP",
"MUTEX",
"CONDVAR",
"JOIN",
"INTR",
"SEM",
"WAITCTX",
"NET_SEND",
"NET_REPLY"
};
unsigned ReqThread_get_extra( void )
{
thread_get_extra_req *req;
char *ret;
procfs_status status;
req = GetInPtr( 0 );
ret = GetOutPtr( 0 );
ret[0] = '\0';
if( req->thread ) {
status.tid = req->thread;
if( devctl( ProcInfo.procfd, DCMD_PROC_TIDSTATUS, &status, sizeof( status ), 0 ) != EOK ) {
dbg_print(( "failed to get extra for thread %ld\n", req->thread ));
strcpy( ret, "error" );
} else {
if( tstate_desc[status.state] ) {
strcpy( ret, tstate_desc[status.state] );
} else {
strcpy( ret, "unknown" );
}
}
} else {
strcpy( ret, "QNX Thread State" );
}
return( strlen( ret ) + 1 );
}
trap_version TRAPENTRY TrapInit( char *parm, char *err, bool remote )
{
trap_version ver;
sigset_t sig_set;
parm = parm;
remote = remote;
/* We use SIGUSR1 to gain control after blocking wait for a process. */
sigemptyset( &sig_set );
sigaddset( &sig_set, SIGUSR1 );
sigprocmask( SIG_BLOCK, &sig_set, NULL );
ProcInfo.save_in = -1;
ProcInfo.save_out = -1;
ProcInfo.node = ND_LOCAL_NODE;
strcpy( ProcInfo.procfs_path, "/proc" );
err[0] = '\0'; /* all ok */
ver.major = TRAP_MAJOR_VERSION;
ver.minor = TRAP_MINOR_VERSION;
ver.remote = FALSE;
OrigPGrp = getpgrp();
return( ver );
}
void TRAPENTRY TrapFini( void )
{
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -