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

📄 ntoacc.c

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
    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 + -