void attach_to_cpu ( void ) { // Stall the CPU before doing anything else. Otherwise, there would be a window of opportunity // for the software to modify the same SPR registers being accessed here. stall_cpu(); uint32_t val; dbg_cpu0_read_spr_e( OR1200_DU_WATCHPOINT_COUNT, &val ); rsp.watchpoint_count = val; dbg_cpu0_read_spr_e( SPR_VR , &rsp.spr_vr ); dbg_cpu0_read_spr_e( SPR_UPR, &rsp.spr_upr ); for ( unsigned i = 0; i < MAX_WATCHPOINT_COUNT; ++i ) rsp.watchpoint_addr[ i ] = 0; printf( "Attached to CPU, SPR VR (version): 0x%08X, SPR UPR (unit presence): 0x%08X\n", rsp.spr_vr, rsp.spr_upr ); // Set up the CPU to break to the Debug Unit on exceptions. // Note that the current OR10 implementation only supports breaking on the l.trap instruction (TRAP exception). dbg_cpu0_write_spr_e( SPR_DSR, SPR_DSR_TE ); // Just in case the single-step mode was activated, reset it. set_single_step_mode( false ); collect_cpu_stop_reason( true ); // Leave the CPU stalled. This is what GDB expects upon connecting. rsp.cpu_poll_speed = CPS_SLOW; }
void process_client_command ( const rsp_buf * const buf ) { if ( rsp.is_target_running ) { // printf( "BREAK received while CPU running.\n" ); if ( buf->data[0] == GDB_RSP_BREAK_CMD ) { stall_cpu(); collect_cpu_stop_reason( true ); send_signal_reply_packet(); rsp.cpu_poll_speed = CPS_SLOW; return; } throw std::runtime_error( "A GDB RSP command was received while the CPU was running, which is an indication " "that the RSP handling got out of sync." ); } assert( rsp.cpu_poll_speed == CPS_SLOW ); switch ( buf->data[0] ) { case GDB_RSP_BREAK_CMD: // The target was not running and a break command was received. This can happen if the user // issues a break (with Ctrl+C) but the CPU just stalled for anothe reason. send_signal_reply_packet(); break; case '!': // Request for extended remote mode, which we do support. send_ok_packet( rsp.client_fd ); break; case '?': send_signal_reply_packet(); break; case 'c': rsp_continue( buf ); break; case 'g': rsp_read_all_regs(); break; case 'H': // Set the thread number of any subsequent operations. // Hc is for step and continue operations, Hg for all other operations. // The thread number can be -1 for all threads, a thread number, or 0 for "just pick any thread". // We only support one thread, so ignore all arguments and just reply "OK" send_ok_packet( rsp.client_fd ); break; case 'k': kill_request(); break; case 'm': rsp_read_mem( buf ); break; case 'M': rsp_write_mem( buf ); break; case 'P': rsp_write_reg( buf ); break; case 'q': // General query packets. rsp_query( buf ); break; case 's': // Single step (one high level instruction). This could be hard without DWARF2 info. rsp_step( buf ); break; case 'v': // Any one of a number of packets to control execution rsp_vpkt( buf ); break; // ----- These are all packets that we have decided not to support ----- case 'z': case 'Z': rsp_watchpoint( buf ); break; case 'D': // Detach GDB. I'm not sure what to do in this case. If you type "detach" in the current // GDB version it does not close the connection and it triggers error message // "A problem internal to GDB has been detected". case 'X': // We don't support binary memory writes. The old code did, so it should not be hard // to port it to this new implementation. This is only an optimisation, as GDB // will fall back to using text-based memory writes (see the 'M' command). send_unknown_command_reply( rsp.client_fd ); break; default: // Assert on all unsupported packets that were not already known to the developer. This helps catch bugs. #ifndef NDEBUG printf( "Unknown RSP packet received: %s\n", format_packet_for_tracing_purposes( buf ).c_str() ); assert( false ); #endif send_unknown_command_reply( rsp.client_fd ); break; } }
void *target_handler(void *arg) { struct timeval tv; fd_set readset; int i, fd, ret, nfds; char cmd; unsigned char target_status; debug("Target handler thread started!\n"); while(1) { // Set this each loop, it may be changed by the select() call tv.tv_sec = 0; tv.tv_usec = 250000; // 1/4 second timeout when polling FD_ZERO(&readset); nfds = 0; pthread_mutex_lock(&pipes_mutex); for(i = 0; i < num_monitor_connections; i++) { fd = connections[i].server_to_monitor_fds[0]; FD_SET(fd, &readset); if(fd > nfds) nfds = fd; } pthread_mutex_unlock(&pipes_mutex); nfds++; // We do not hold the pipes_mutex during the select(), so it is possible that some of // the pipes in the readset will go away while we block. This is fine, as we re-take // the lock below and iterate through the (changed) connections[] array, which will // ignore any pipes which have closed, even if they are in the readset. ret = select(nfds, &readset, NULL, NULL, &tv); if(ret == -1) // error { // We may get an EBADF if a server un-registers its pipes while we're in the select() // (very likely). So, ignore EBADF unless there's a problem that needs debugged. if(errno != EBADF) perror("select()"); else { debug("Monitor thread got EBADF in select(). Server unregistration, or real problem?"); } } else if(ret != 0) // fd ready (ret == 0 on timeout) { debug("Monitor thread got data\n"); pthread_mutex_lock(&pipes_mutex); for(i = 0; i < num_monitor_connections; i++) { debug("Monitor checking incoming connection %i\n", i); fd = connections[i].server_to_monitor_fds[0]; if(FD_ISSET(fd, &readset)) { ret = read(fd, &cmd, 1); debug("Target monitor thread got command \'%c\' (0x%X)\n", cmd, cmd); if(ret == 1) { if(cmd == 'S') { if(target_is_running) stall_cpu(1); notify_listeners("H", 1); } else if(cmd == 'U') { if(!target_is_running) stall_cpu(0); notify_listeners("R", 1); } else { fprintf(stderr, "Target monitor thread got unknown command \'%c\' (0x%X)\n", cmd, cmd); } } else { fprintf(stderr, "Monitor thread failed to read from ready descriptor!\n"); } } // if FD_ISSET() } // for i = 0 to num_monitor_connections pthread_mutex_unlock(&pipes_mutex); // We got a command. Either the target is now stalled and we don't need to poll, // or the target just started and we should wait a bit before polling. continue; } // else if (ret != 0) if(target_is_running) { debug("Monitor polling hardware!\n"); // Poll target hardware ret = dbg_cpu0_read_ctrl(0, &target_status); if(ret != APP_ERR_NONE) fprintf(stderr, "ERROR 0x%X while polling target CPU status\n", ret); else { if(target_status & 0x01) // Did we get the stall bit? Bit 0 is STALL bit. { debug("Monitor poll found CPU stalled!\n"); target_is_running = 0; pthread_mutex_lock(&pipes_mutex); notify_listeners("H", 1); pthread_mutex_unlock(&pipes_mutex); } } } // if(target_is_running) } // while(1), main loop fprintf(stderr, "Target monitor thread exiting!!"); return arg; }