LCOV - code coverage report
Current view: directory - src/trusted/debug_stub - target.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 541 425 78.6 %
Date: 2014-07-02 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : #include <string.h>
       8                 : #include <stdlib.h>
       9                 : #include <stdio.h>
      10                 : 
      11                 : #include <algorithm>
      12                 : 
      13                 : #include "native_client/src/include/nacl_scoped_ptr.h"
      14                 : #include "native_client/src/shared/platform/nacl_check.h"
      15                 : #include "native_client/src/shared/platform/nacl_exit.h"
      16                 : #include "native_client/src/shared/platform/nacl_log.h"
      17                 : #include "native_client/src/trusted/debug_stub/abi.h"
      18                 : #include "native_client/src/trusted/debug_stub/packet.h"
      19                 : #include "native_client/src/trusted/debug_stub/platform.h"
      20                 : #include "native_client/src/trusted/debug_stub/session.h"
      21                 : #include "native_client/src/trusted/debug_stub/target.h"
      22                 : #include "native_client/src/trusted/debug_stub/thread.h"
      23                 : #include "native_client/src/trusted/debug_stub/util.h"
      24                 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
      25                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      26                 : #include "native_client/src/trusted/service_runtime/thread_suspension.h"
      27                 : 
      28                 : #if NACL_WINDOWS
      29                 : #define snprintf sprintf_s
      30                 : #endif
      31                 : 
      32                 : using std::string;
      33                 : 
      34                 : using port::IPlatform;
      35                 : using port::IThread;
      36                 : using port::MutexLock;
      37                 : 
      38                 : namespace gdb_rsp {
      39                 : 
      40                 : 
      41                 : // Arbitrary descriptor to return when the main nexe is opened.
      42                 : // This can be shared as the file connections are stateless.
      43                 : static const char kMainNexeFilename[] = "nexe";
      44                 : static const char kIrtNexeFilename[] = "irt";
      45                 : static const uint64_t kMainNexeFd = 123;
      46                 : static const uint64_t kIrtNexeFd = 234;
      47                 : 
      48                 : // The GDB debug protocol specifies particular values for return values,
      49                 : // errno values, and mode flags. Explicitly defining the subset used herein.
      50                 : static const uint64_t kGdbErrorResult = static_cast<uint64_t>(-1);
      51                 : static const uint64_t kGdbO_RDONLY = 0;
      52                 : static const uint64_t kGdbEPERM = 1;
      53                 : static const uint64_t kGdbENOENT = 2;
      54                 : static const uint64_t kGdbEBADF = 9;
      55                 : 
      56                 : // Assume a buffer size that matches GDB's actual current request size.
      57                 : static const size_t kGdbPreadChunkSize = 4096;
      58                 : 
      59                 : 
      60              19 : Target::Target(struct NaClApp *nap, const Abi* abi)
      61                 :   : nap_(nap),
      62                 :     abi_(abi),
      63                 :     session_(NULL),
      64                 :     initial_breakpoint_addr_(0),
      65                 :     ctx_(NULL),
      66                 :     cur_signal_(0),
      67                 :     sig_thread_(0),
      68                 :     reg_thread_(0),
      69                 :     step_over_breakpoint_thread_(0),
      70                 :     all_threads_suspended_(false),
      71                 :     detaching_(false),
      72              19 :     should_exit_(false) {
      73              19 :   if (NULL == abi_) abi_ = Abi::Get();
      74              19 : }
      75                 : 
      76               0 : Target::~Target() {
      77               0 :   Destroy();
      78               0 : }
      79                 : 
      80              19 : bool Target::Init() {
      81              19 :   string targ_xml = "l<target><architecture>";
      82                 : 
      83              19 :   targ_xml += abi_->GetName();
      84              19 :   targ_xml += "</architecture><osabi>NaCl</osabi>";
      85              19 :   targ_xml += abi_->GetTargetXml();
      86              19 :   targ_xml += "</target>";
      87                 : 
      88                 :   // Set a more specific result which won't change.
      89              19 :   properties_["target.xml"] = targ_xml;
      90              38 :   properties_["Supported"] =
      91              19 :     "PacketSize=1000;qXfer:features:read+";
      92                 : 
      93              19 :   NaClXMutexCtor(&mutex_);
      94              19 :   ctx_ = new uint8_t[abi_->GetContextSize()];
      95                 : 
      96              19 :   initial_breakpoint_addr_ = (uint32_t) nap_->initial_entry_pt;
      97              19 :   if (!AddBreakpoint(initial_breakpoint_addr_))
      98               0 :     return false;
      99              19 :   return true;
     100                 : }
     101                 : 
     102               0 : void Target::Destroy() {
     103               0 :   NaClMutexDtor(&mutex_);
     104                 : 
     105               0 :   delete[] ctx_;
     106               0 : }
     107                 : 
     108              70 : bool Target::AddBreakpoint(uint32_t user_address) {
     109              70 :   const Abi::BPDef *bp = abi_->GetBreakpointDef();
     110                 : 
     111                 :   // If we already have a breakpoint here then don't add it
     112              70 :   if (breakpoint_map_.find(user_address) != breakpoint_map_.end())
     113               0 :     return false;
     114                 : 
     115              70 :   uintptr_t sysaddr = NaClUserToSysAddrRange(nap_, user_address, bp->size_);
     116              70 :   if (sysaddr == kNaClBadAddress)
     117               0 :     return false;
     118                 :   // We allow setting breakpoints in the code area but not the data area.
     119              70 :   if (user_address + bp->size_ > nap_->dynamic_text_end)
     120               0 :     return false;
     121                 : 
     122                 :   // We add the breakpoint by overwriting the start of an instruction
     123                 :   // with a breakpoint instruction.  (At least, we assume that we have
     124                 :   // been given the address of the start of an instruction.)  In order
     125                 :   // to be able to remove the breakpoint later, we save a copy of the
     126                 :   // locations we are overwriting into breakpoint_map_.
     127              70 :   uint8_t *data = new uint8_t[bp->size_];
     128                 : 
     129                 :   // Copy the old code from here
     130              70 :   if (!IPlatform::GetMemory(sysaddr, bp->size_, data)) {
     131               1 :     delete[] data;
     132               1 :     return false;
     133                 :   }
     134              69 :   if (!IPlatform::SetMemory(nap_, sysaddr, bp->size_, bp->code_)) {
     135               0 :     delete[] data;
     136               0 :     return false;
     137                 :   }
     138                 : 
     139              69 :   breakpoint_map_[user_address] = data;
     140              69 :   return true;
     141                 : }
     142                 : 
     143              69 : bool Target::RemoveBreakpoint(uint32_t user_address) {
     144              69 :   const Abi::BPDef *bp_def = abi_->GetBreakpointDef();
     145                 : 
     146              69 :   BreakpointMap_t::iterator iter = breakpoint_map_.find(user_address);
     147              69 :   if (iter == breakpoint_map_.end())
     148               0 :     return false;
     149                 : 
     150              69 :   uintptr_t sysaddr = NaClUserToSys(nap_, user_address);
     151              69 :   uint8_t *data = iter->second;
     152                 :   // Copy back the old code, and free the data
     153              69 :   if (!IPlatform::SetMemory(nap_, sysaddr, bp_def->size_, data)) {
     154               0 :     NaClLog(LOG_ERROR, "Failed to undo breakpoint.\n");
     155               0 :     return false;
     156                 :   }
     157              69 :   delete[] data;
     158              69 :   breakpoint_map_.erase(iter);
     159              69 :   return true;
     160                 : }
     161                 : 
     162              93 : void Target::CopyFaultSignalFromAppThread(IThread *thread) {
     163              93 :   if (thread->GetFaultSignal() == 0 && thread->HasThreadFaulted()) {
     164                 :     int signal =
     165              84 :         IThread::ExceptionToSignal(thread->GetAppThread()->fault_signal);
     166                 :     // If a thread hits a breakpoint, we want to ensure that it is
     167                 :     // reported as SIGTRAP rather than SIGSEGV.  This is necessary
     168                 :     // because we use HLT (which produces SIGSEGV) rather than the
     169                 :     // more usual INT3 (which produces SIGTRAP) on x86, in order to
     170                 :     // work around a Mac OS X bug.  Similarly, on ARM we use an
     171                 :     // illegal instruction (which produces SIGILL) rather than the
     172                 :     // more usual BKPT (which produces SIGTRAP).
     173                 :     //
     174                 :     // We need to check each thread to see whether it hit a
     175                 :     // breakpoint.  We record this on the thread object because:
     176                 :     //  * We need to check the threads before accepting any commands
     177                 :     //    from GDB which might remove breakpoints from
     178                 :     //    breakpoint_map_, which would remove our ability to tell
     179                 :     //    whether a thread hit a breakpoint.
     180                 :     //  * Although we deliver fault events to GDB one by one, we might
     181                 :     //    have multiple threads that have hit breakpoints.
     182              84 :     if ((NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 &&
     183                 :          signal == NACL_ABI_SIGSEGV) ||
     184                 :         (NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm &&
     185                 :          signal == NACL_ABI_SIGILL)) {
     186                 :       // Casting to uint32_t is necessary to drop the top 32 bits of
     187                 :       // %rip on x86-64.
     188              49 :       uint32_t prog_ctr = (uint32_t) thread->GetContext()->prog_ctr;
     189              49 :       if (breakpoint_map_.find(prog_ctr) != breakpoint_map_.end()) {
     190              49 :         signal = NACL_ABI_SIGTRAP;
     191                 :       }
     192                 :     }
     193              84 :     thread->SetFaultSignal(signal);
     194                 :   }
     195              93 : }
     196                 : 
     197              84 : void Target::RemoveInitialBreakpoint() {
     198              84 :   if (initial_breakpoint_addr_ != 0) {
     199              19 :     if (!RemoveBreakpoint(initial_breakpoint_addr_)) {
     200                 :       NaClLog(LOG_FATAL,
     201               0 :               "RemoveInitialBreakpoint: Failed to remove breakpoint\n");
     202                 :     }
     203              19 :     initial_breakpoint_addr_ = 0;
     204                 :   }
     205              84 : }
     206                 : 
     207                 : // When the debugger reads memory, we want to report the original
     208                 : // memory contents without the modifications we made to add
     209                 : // breakpoints.  This function undoes the modifications from a copy of
     210                 : // memory.
     211             219 : void Target::EraseBreakpointsFromCopyOfMemory(uint32_t user_address,
     212                 :                                               uint8_t *data, uint32_t size) {
     213             219 :   uint32_t user_end = user_address + size;
     214             219 :   const Abi::BPDef *bp = abi_->GetBreakpointDef();
     215             592 :   for (BreakpointMap_t::iterator iter = breakpoint_map_.begin();
     216             296 :        iter != breakpoint_map_.end();
     217                 :        ++iter) {
     218              77 :     uint32_t breakpoint_address = iter->first;
     219              77 :     uint32_t breakpoint_end = breakpoint_address + bp->size_;
     220              77 :     uint8_t *original_data = iter->second;
     221                 : 
     222              77 :     uint32_t overlap_start = std::max(user_address, breakpoint_address);
     223              77 :     uint32_t overlap_end = std::min(user_end, breakpoint_end);
     224              77 :     if (overlap_start < overlap_end) {
     225              33 :       uint8_t *dest = data + (overlap_start - user_address);
     226              33 :       uint8_t *src = original_data + (overlap_start - breakpoint_address);
     227              33 :       size_t copy_size = overlap_end - overlap_start;
     228                 :       // Sanity check: do some bounds checks.
     229              33 :       CHECK(data <= dest && dest + copy_size <= data + size);
     230              33 :       CHECK(original_data <= src
     231                 :             && src + copy_size <= original_data + bp->size_);
     232              33 :       memcpy(dest, src, copy_size);
     233                 :     }
     234                 :   }
     235             219 : }
     236                 : 
     237              31 : void Target::Run(Session *ses) {
     238              31 :   NaClXMutexLock(&mutex_);
     239              31 :   session_ = ses;
     240              31 :   NaClXMutexUnlock(&mutex_);
     241                 : 
     242           10340 :   do {
     243           10356 :     WaitForDebugEvent();
     244                 : 
     245                 :     // Lock to prevent anyone else from modifying threads
     246                 :     // or updating the signal information.
     247           10356 :     MutexLock lock(&mutex_);
     248                 : 
     249           10356 :     ProcessDebugEvent();
     250           10356 :     ProcessCommands();
     251           10340 :   } while (session_->Connected());
     252                 : 
     253              15 :   NaClXMutexLock(&mutex_);
     254              15 :   session_ = NULL;
     255              15 :   NaClXMutexUnlock(&mutex_);
     256              15 : }
     257                 : 
     258             160 : bool Target::IsInitialBreakpointActive() {
     259             160 :   return initial_breakpoint_addr_ != 0;
     260                 : }
     261                 : 
     262           10356 : void Target::WaitForDebugEvent() {
     263           10356 :   if (all_threads_suspended_) {
     264                 :     // If all threads are suspended (which may be left over from a previous
     265                 :     // connection), we are already ready to handle commands from GDB.
     266           10368 :     return;
     267                 :   }
     268                 :   // Wait for either:
     269                 :   //   * an untrusted thread to fault (or single-step)
     270                 :   //   * an interrupt from GDB
     271                 :   bool ignore_input_from_gdb = step_over_breakpoint_thread_ != 0 ||
     272           10344 :     IsInitialBreakpointActive();
     273           10344 :   session_->WaitForDebugStubEvent(nap_, ignore_input_from_gdb);
     274                 : }
     275                 : 
     276           10356 : void Target::ProcessDebugEvent() {
     277           10356 :   if (all_threads_suspended_) {
     278                 :     // We are already in a suspended state.
     279              12 :     return;
     280           10344 :   } else if (step_over_breakpoint_thread_ != 0) {
     281                 :     // We are waiting for a specific thread to fault while all other
     282                 :     // threads are suspended.  Note that faulted_thread_count might
     283                 :     // be >1, because multiple threads can fault simultaneously
     284                 :     // before the debug stub gets a chance to suspend all threads.
     285                 :     // This is why we must check the status of a specific thread --
     286                 :     // we cannot call UnqueueAnyFaultedThread() and expect it to
     287                 :     // return step_over_breakpoint_thread_.
     288           10270 :     IThread *thread = threads_[step_over_breakpoint_thread_];
     289           10270 :     if (!thread->HasThreadFaulted()) {
     290                 :       // The thread has not faulted.  Nothing to do, so try again.
     291                 :       // Note that we do not respond to input from GDB while in this
     292                 :       // state.
     293                 :       // TODO(mseaborn): We should allow GDB to interrupt execution.
     294           10259 :       return;
     295                 :     }
     296                 :     // All threads but one are already suspended.  We only need to
     297                 :     // suspend the single thread that we allowed to run.
     298              11 :     thread->SuspendThread();
     299              11 :     CopyFaultSignalFromAppThread(thread);
     300              11 :     cur_signal_ = thread->GetFaultSignal();
     301              11 :     thread->UnqueueFaultedThread();
     302              11 :     sig_thread_ = step_over_breakpoint_thread_;
     303              11 :     reg_thread_ = step_over_breakpoint_thread_;
     304              11 :     step_over_breakpoint_thread_ = 0;
     305              74 :   } else if (nap_->faulted_thread_count != 0) {
     306                 :     // At least one untrusted thread has got an exception.  First we
     307                 :     // need to ensure that all threads are suspended.  Then we can
     308                 :     // retrieve a thread from the set of faulted threads.
     309              73 :     SuspendAllThreads();
     310              73 :     UnqueueAnyFaultedThread(&sig_thread_, &cur_signal_);
     311              73 :     reg_thread_ = sig_thread_;
     312                 :   } else {
     313                 :     // Otherwise look for messages from GDB.  To fix a potential
     314                 :     // race condition, we don't do this on the first run, because in
     315                 :     // that case we are waiting for the initial breakpoint to be
     316                 :     // reached.  We don't want GDB to observe states where the
     317                 :     // (internal) initial breakpoint is still registered or where
     318                 :     // the initial thread is suspended in NaClStartThreadInApp()
     319                 :     // before executing its first untrusted instruction.
     320               1 :     if (IsInitialBreakpointActive() || !session_->IsDataAvailable()) {
     321                 :       // No input from GDB.  Nothing to do, so try again.
     322               0 :       return;
     323                 :     }
     324                 :     // GDB should have tried to interrupt the target.
     325                 :     // See http://sourceware.org/gdb/current/onlinedocs/gdb/Interrupts.html
     326                 :     // TODO(eaeltsin): should we verify the interrupt sequence?
     327                 : 
     328                 :     // Indicate we have no current thread.
     329                 :     // TODO(eaeltsin): or pick any thread? Add a test.
     330                 :     // See http://code.google.com/p/nativeclient/issues/detail?id=2743
     331               1 :     sig_thread_ = 0;
     332               1 :     SuspendAllThreads();
     333                 :   }
     334                 : 
     335              85 :   bool initial_breakpoint_was_active = IsInitialBreakpointActive();
     336                 : 
     337              85 :   if (sig_thread_ != 0) {
     338                 :     // Reset single stepping.
     339              84 :     threads_[sig_thread_]->SetStep(false);
     340              84 :     RemoveInitialBreakpoint();
     341                 :   }
     342                 : 
     343                 :   // Next update the current thread info
     344                 :   char tmp[16];
     345              85 :   snprintf(tmp, sizeof(tmp), "QC%x", sig_thread_);
     346              85 :   properties_["C"] = tmp;
     347                 : 
     348              85 :   if (!initial_breakpoint_was_active) {
     349                 :     // First time on a connection, we don't send the signal.
     350                 :     // All other times, send the signal that triggered us.
     351              66 :     Packet pktOut;
     352              66 :     SetStopReply(&pktOut);
     353              66 :     session_->SendPacketOnly(&pktOut);
     354                 :   }
     355                 : 
     356              85 :   all_threads_suspended_ = true;
     357                 : }
     358                 : 
     359           10356 : void Target::ProcessCommands() {
     360           10356 :   if (!all_threads_suspended_) {
     361                 :     // Don't process commands if we haven't stopped all threads.
     362           10259 :     return;
     363                 :   }
     364                 : 
     365                 :   // Now we are ready to process commands.
     366                 :   // Loop through packets until we process a continue packet or a detach.
     367              97 :   Packet recv, reply;
     368             831 :   do {
     369             915 :     if (!session_->GetPacket(&recv))
     370              13 :       continue;
     371             902 :     reply.Clear();
     372             902 :     if (ProcessPacket(&recv, &reply)) {
     373                 :       // If this is a continue type command, break out of this loop.
     374              66 :       break;
     375                 :     }
     376                 :     // Otherwise send the response.
     377             836 :     session_->SendPacket(&reply);
     378                 : 
     379             836 :     if (detaching_) {
     380               2 :       detaching_ = false;
     381               2 :       session_->Disconnect();
     382               2 :       Resume();
     383                 :       return;
     384                 :     }
     385                 : 
     386             834 :     if (should_exit_) {
     387              16 :       NaClExit(-9);
     388                 :     }
     389             831 :   } while (session_->Connected());
     390                 : 
     391              79 :   if (session_->Connected()) {
     392                 :     // Continue if we're still connected.
     393              66 :     Resume();
     394              81 :   }
     395                 : }
     396                 : 
     397              68 : void Target::Resume() {
     398                 :   // Reset the signal value
     399              68 :   cur_signal_ = 0;
     400                 : 
     401                 :   // TODO(eaeltsin): it might make sense to resume signaled thread before
     402                 :   // others, though it is not required by GDB docs.
     403              68 :   if (step_over_breakpoint_thread_ == 0) {
     404              57 :     ResumeAllThreads();
     405                 :   } else {
     406                 :     // Resume one thread while leaving all others suspended.
     407              11 :     threads_[step_over_breakpoint_thread_]->ResumeThread();
     408                 :   }
     409                 : 
     410              68 :   all_threads_suspended_ = false;
     411              68 : }
     412                 : 
     413              95 : void Target::SetStopReply(Packet *pktOut) const {
     414              95 :   pktOut->AddRawChar('T');
     415              95 :   pktOut->AddWord8(cur_signal_);
     416                 : 
     417                 :   // gdbserver handles GDB interrupt by sending SIGINT to the debuggee, thus
     418                 :   // GDB interrupt is also a case of a signalled thread.
     419                 :   // At the moment we handle GDB interrupt differently, without using a signal,
     420                 :   // so in this case sig_thread_ is 0.
     421                 :   // This might seem weird to GDB, so at least avoid reporting tid 0.
     422                 :   // TODO(eaeltsin): http://code.google.com/p/nativeclient/issues/detail?id=2743
     423              95 :   if (sig_thread_ != 0) {
     424                 :     // Add 'thread:<tid>;' pair. Note terminating ';' is required.
     425              94 :     pktOut->AddString("thread:");
     426              94 :     pktOut->AddNumberSep(sig_thread_, ';');
     427                 :   }
     428              95 : }
     429                 : 
     430                 : 
     431               1 : bool Target::GetFirstThreadId(uint32_t *id) {
     432               1 :   threadItr_ = threads_.begin();
     433               1 :   return GetNextThreadId(id);
     434                 : }
     435                 : 
     436               3 : bool Target::GetNextThreadId(uint32_t *id) {
     437               3 :   if (threadItr_ == threads_.end()) return false;
     438                 : 
     439               2 :   *id = (*threadItr_).first;
     440               2 :   threadItr_++;
     441                 : 
     442               2 :   return true;
     443                 : }
     444                 : 
     445                 : 
     446             226 : uint64_t Target::AdjustUserAddr(uint64_t addr) {
     447                 :   // On x86-64, GDB sometimes uses memory addresses with the %r15
     448                 :   // sandbox base included, so we must accept these addresses.
     449                 :   // TODO(eaeltsin): Fix GDB to not use addresses with %r15 added.
     450                 :   if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64 &&
     451                 :       NaClIsUserAddr(nap_, (uintptr_t) addr)) {
     452                 :     return NaClSysToUser(nap_, (uintptr_t) addr);
     453                 :   }
     454                 :   // Otherwise, we expect an untrusted address.
     455             226 :   return addr;
     456                 : }
     457                 : 
     458               0 : void Target::EmitFileError(Packet *pktOut, int code) {
     459               0 :   pktOut->AddString("F");
     460               0 :   pktOut->AddNumberSep(kGdbErrorResult, ',');
     461               0 :   pktOut->AddNumberSep(code, 0);
     462               0 : }
     463                 : 
     464              76 : void Target::ProcessFilePacket(Packet *pktIn, Packet *pktOut, ErrDef *err) {
     465              76 :   std::string cmd;
     466              76 :   if (!pktIn->GetStringSep(&cmd, ':')) {
     467               0 :     *err = BAD_FORMAT;
     468                 :     return;
     469                 :   }
     470              76 :   CHECK(cmd == "File");
     471              76 :   std::string subcmd;
     472              76 :   if (!pktIn->GetStringSep(&subcmd, ':')) {
     473               0 :     *err = BAD_FORMAT;
     474                 :     return;
     475                 :   }
     476              76 :   if (subcmd == "open") {
     477               1 :     std::string filename;
     478                 :     char sep;
     479                 :     uint64_t flags;
     480                 :     uint64_t mode;
     481               4 :     if (!pktIn->GetHexString(&filename) ||
     482               1 :         !pktIn->GetRawChar(&sep) ||
     483                 :         sep != ',' ||
     484               1 :         !pktIn->GetNumberSep(&flags, NULL) ||
     485               1 :         !pktIn->GetNumberSep(&mode, NULL)) {
     486               0 :       *err = BAD_ARGS;
     487                 :       return;
     488                 :     }
     489               1 :     if (filename == kMainNexeFilename) {
     490               1 :       if (flags == kGdbO_RDONLY) {
     491               1 :         pktOut->AddString("F");
     492               1 :         pktOut->AddNumberSep(kMainNexeFd, 0);
     493                 :       } else {
     494               0 :         EmitFileError(pktOut, kGdbEPERM);
     495                 :       }
     496               0 :     } else if (filename == kIrtNexeFilename) {
     497               0 :       if (flags == kGdbO_RDONLY) {
     498               0 :         pktOut->AddString("F");
     499               0 :         pktOut->AddNumberSep(kIrtNexeFd, 0);
     500                 :       } else {
     501               0 :         EmitFileError(pktOut, kGdbEPERM);
     502                 :       }
     503                 :     } else {
     504               0 :       EmitFileError(pktOut, kGdbENOENT);
     505                 :     }
     506               1 :     return;
     507              75 :   } else if (subcmd == "close") {
     508                 :     uint64_t fd;
     509               1 :     if (!pktIn->GetNumberSep(&fd, NULL)) {
     510               0 :       *err = BAD_ARGS;
     511                 :       return;
     512                 :     }
     513               1 :     if (fd == kMainNexeFd) {
     514               1 :       pktOut->AddString("F");
     515               1 :       pktOut->AddNumberSep(0, 0);
     516               0 :     } else if (fd == kIrtNexeFd) {
     517               0 :       pktOut->AddString("F");
     518               0 :       pktOut->AddNumberSep(0, 0);
     519                 :     } else {
     520               0 :       EmitFileError(pktOut, kGdbEBADF);
     521                 :     }
     522                 :     return;
     523              74 :   } else if (subcmd == "pread") {
     524                 :     uint64_t fd;
     525                 :     uint64_t count;
     526                 :     uint64_t offset;
     527              74 :     std::string data;
     528             222 :     if (!pktIn->GetNumberSep(&fd, NULL) ||
     529              74 :         !pktIn->GetNumberSep(&count, NULL) ||
     530              74 :         !pktIn->GetNumberSep(&offset, NULL)) {
     531               0 :       *err = BAD_ARGS;
     532                 :       return;
     533                 :     }
     534                 :     NaClDesc *desc;
     535              74 :     if (fd == kMainNexeFd) {
     536              74 :       desc = nap_->main_nexe_desc;
     537               0 :     } else if (fd == kIrtNexeFd) {
     538               0 :       desc = nap_->irt_nexe_desc;
     539                 :     } else {
     540               0 :       EmitFileError(pktOut, kGdbEBADF);
     541                 :       return;
     542                 :     }
     543              74 :     CHECK(NULL != desc);
     544              74 :     if (count > kGdbPreadChunkSize) {
     545               0 :       count = kGdbPreadChunkSize;
     546                 :     }
     547              74 :     nacl::scoped_array<char> buffer(new char[kGdbPreadChunkSize]);
     548                 :     ssize_t result = (*NACL_VTBL(NaClDesc, desc)->PRead)(
     549              74 :         desc, buffer.get(),
     550                 :         static_cast<size_t>(count),
     551             148 :         static_cast<nacl_off64_t>(offset));
     552              74 :     pktOut->AddString("F");
     553              74 :     if (result < 0) {
     554               0 :       pktOut->AddNumberSep(kGdbErrorResult, ',');
     555               0 :       pktOut->AddNumberSep(static_cast<uint64_t>(-result), 0);
     556                 :     } else {
     557              74 :       pktOut->AddNumberSep(static_cast<uint64_t>(result), ';');
     558              74 :       pktOut->AddEscapedData(buffer.get(), static_cast<size_t>(result));
     559                 :     }
     560              74 :     return;
     561                 :   }
     562               0 :   NaClLog(LOG_ERROR, "Unknown vFile command: %s\n", pktIn->GetPayload());
     563               0 :   *err = BAD_FORMAT;
     564                 : }
     565                 : 
     566             902 : bool Target::ProcessPacket(Packet* pktIn, Packet* pktOut) {
     567                 :   char cmd;
     568             902 :   int32_t seq = -1;
     569             902 :   ErrDef  err = NONE;
     570                 : 
     571                 :   // Clear the outbound message
     572             902 :   pktOut->Clear();
     573                 : 
     574                 :   // Pull out the sequence.
     575             902 :   pktIn->GetSequence(&seq);
     576             902 :   if (seq != -1) pktOut->SetSequence(seq);
     577                 : 
     578                 :   // Find the command
     579             902 :   pktIn->GetRawChar(&cmd);
     580                 : 
     581             902 :   switch (cmd) {
     582                 :     // IN : $?
     583                 :     // OUT: $Sxx
     584                 :     case '?':
     585              29 :       SetStopReply(pktOut);
     586              29 :       break;
     587                 : 
     588                 :     case 'c':
     589               0 :       return true;
     590                 : 
     591                 :     // IN : $D
     592                 :     // OUT: $OK
     593                 :     case 'D':
     594               2 :       Detach();
     595               2 :       pktOut->AddString("OK");
     596               2 :       return false;
     597                 : 
     598                 :     // IN : $k
     599                 :     // OUT: $OK
     600                 :     case 'k':
     601              16 :       Kill();
     602              16 :       pktOut->AddString("OK");
     603              16 :       return false;
     604                 : 
     605                 :     // IN : $g
     606                 :     // OUT: $xx...xx
     607                 :     case 'g': {
     608              99 :       IThread *thread = GetRegThread();
     609              99 :       if (NULL == thread) {
     610               0 :         err = BAD_ARGS;
     611               0 :         break;
     612                 :       }
     613                 : 
     614                 :       // Copy OS preserved registers to GDB payload
     615            1683 :       for (uint32_t a = 0; a < abi_->GetRegisterCount(); a++) {
     616            1584 :         const Abi::RegDef *def = abi_->GetRegisterDef(a);
     617            1584 :         thread->GetRegister(a, &ctx_[def->offset_], def->bytes_);
     618                 :       }
     619                 : 
     620              99 :       pktOut->AddBlock(ctx_, abi_->GetContextSize());
     621              99 :       break;
     622                 :     }
     623                 : 
     624                 :     // IN : $Gxx..xx
     625                 :     // OUT: $OK
     626                 :     case 'G': {
     627              13 :       IThread *thread = GetRegThread();
     628              13 :       if (NULL == thread) {
     629               0 :         err = BAD_ARGS;
     630               0 :         break;
     631                 :       }
     632                 : 
     633              13 :       pktIn->GetBlock(ctx_, abi_->GetContextSize());
     634                 : 
     635                 :       // GDB payload to OS registers
     636             221 :       for (uint32_t a = 0; a < abi_->GetRegisterCount(); a++) {
     637             208 :         const Abi::RegDef *def = abi_->GetRegisterDef(a);
     638             208 :         thread->SetRegister(a, &ctx_[def->offset_], def->bytes_);
     639                 :       }
     640                 : 
     641              13 :       pktOut->AddString("OK");
     642              13 :       break;
     643                 :     }
     644                 : 
     645                 :     // IN : $H(c/g)(-1,0,xxxx)
     646                 :     // OUT: $OK
     647                 :     case 'H': {
     648                 :         char type;
     649                 :         uint64_t id;
     650                 : 
     651              63 :         if (!pktIn->GetRawChar(&type)) {
     652               0 :           err = BAD_FORMAT;
     653               0 :           break;
     654                 :         }
     655              63 :         if (!pktIn->GetNumberSep(&id, 0)) {
     656               0 :           err = BAD_FORMAT;
     657               0 :           break;
     658                 :         }
     659                 : 
     660              63 :         if (threads_.begin() == threads_.end()) {
     661               0 :             err = BAD_ARGS;
     662               0 :             break;
     663                 :         }
     664                 : 
     665                 :         // If we are using "any" get the first thread
     666              63 :         if (id == static_cast<uint64_t>(-1)) id = threads_.begin()->first;
     667                 : 
     668                 :         // Verify that we have the thread
     669              63 :         if (threads_.find(static_cast<uint32_t>(id)) == threads_.end()) {
     670              29 :           err = BAD_ARGS;
     671              29 :           break;
     672                 :         }
     673                 : 
     674              34 :         pktOut->AddString("OK");
     675              34 :         switch (type) {
     676                 :           case 'g':
     677               5 :             reg_thread_ = static_cast<uint32_t>(id);
     678               5 :             break;
     679                 : 
     680                 :           case 'c':
     681                 :             // 'c' is deprecated in favor of vCont.
     682                 :           default:
     683              29 :             err = BAD_ARGS;
     684              29 :             break;
     685                 :         }
     686              34 :         break;
     687                 :       }
     688                 : 
     689                 :     // IN : $maaaa,llll
     690                 :     // OUT: $xx..xx
     691                 :     case 'm': {
     692                 :         uint64_t user_addr;
     693                 :         uint64_t wlen;
     694                 :         uint32_t len;
     695             221 :         if (!pktIn->GetNumberSep(&user_addr, 0)) {
     696               0 :           err = BAD_FORMAT;
     697               0 :           break;
     698                 :         }
     699             221 :         if (!pktIn->GetNumberSep(&wlen, 0)) {
     700               0 :           err = BAD_FORMAT;
     701               0 :           break;
     702                 :         }
     703             221 :         user_addr = AdjustUserAddr(user_addr);
     704                 :         uint64_t sys_addr = NaClUserToSysAddrRange(nap_, (uintptr_t) user_addr,
     705             221 :                                                    (size_t) wlen);
     706             221 :         if (sys_addr == kNaClBadAddress) {
     707               0 :           err = FAILED;
     708               0 :           break;
     709                 :         }
     710                 : 
     711             221 :         len = static_cast<uint32_t>(wlen);
     712             221 :         nacl::scoped_array<uint8_t> block(new uint8_t[len]);
     713             221 :         if (!port::IPlatform::GetMemory(sys_addr, len, block.get())) {
     714               2 :           err = FAILED;
     715                 :           break;
     716                 :         }
     717                 :         EraseBreakpointsFromCopyOfMemory((uint32_t) user_addr,
     718             219 :                                          block.get(), len);
     719                 : 
     720             219 :         pktOut->AddBlock(block.get(), len);
     721             221 :         break;
     722                 :       }
     723                 : 
     724                 :     // IN : $Maaaa,llll:xx..xx
     725                 :     // OUT: $OK
     726                 :     case 'M':  {
     727                 :         uint64_t user_addr;
     728                 :         uint64_t wlen;
     729                 :         uint32_t len;
     730                 : 
     731               5 :         if (!pktIn->GetNumberSep(&user_addr, 0)) {
     732               0 :           err = BAD_FORMAT;
     733               0 :           break;
     734                 :         }
     735               5 :         if (!pktIn->GetNumberSep(&wlen, 0)) {
     736               0 :           err = BAD_FORMAT;
     737               0 :           break;
     738                 :         }
     739               5 :         user_addr = AdjustUserAddr(user_addr);
     740                 :         uint64_t sys_addr = NaClUserToSysAddrRange(nap_, (uintptr_t) user_addr,
     741               5 :                                                    (size_t) wlen);
     742               5 :         if (sys_addr == kNaClBadAddress) {
     743               0 :           err = FAILED;
     744               0 :           break;
     745                 :         }
     746               5 :         len = static_cast<uint32_t>(wlen);
     747                 :         // We disallow the debugger from modifying code.
     748               5 :         if (user_addr < nap_->dynamic_text_end) {
     749               0 :           err = FAILED;
     750               0 :           break;
     751                 :         }
     752                 : 
     753               5 :         nacl::scoped_array<uint8_t> block(new uint8_t[len]);
     754               5 :         pktIn->GetBlock(block.get(), len);
     755                 : 
     756               5 :         if (!port::IPlatform::SetMemory(nap_, sys_addr, len, block.get())) {
     757               0 :           err = FAILED;
     758                 :           break;
     759                 :         }
     760                 : 
     761               5 :         pktOut->AddString("OK");
     762               5 :         break;
     763                 :       }
     764                 : 
     765                 :     case 'q': {
     766             180 :       string tmp;
     767             180 :       const char *str = &pktIn->GetPayload()[1];
     768             180 :       stringvec toks = StringSplit(str, ":;");
     769             180 :       PropertyMap_t::const_iterator itr = properties_.find(toks[0]);
     770                 : 
     771                 :       // If this is a thread query
     772             180 :       if (!strcmp(str, "fThreadInfo") || !strcmp(str, "sThreadInfo")) {
     773                 :         uint32_t curr;
     774               3 :         bool more = false;
     775               3 :         if (str[0] == 'f') {
     776               1 :           more = GetFirstThreadId(&curr);
     777                 :         } else {
     778               2 :           more = GetNextThreadId(&curr);
     779                 :         }
     780                 : 
     781               3 :         if (!more) {
     782               1 :           pktOut->AddString("l");
     783                 :         } else {
     784               2 :           pktOut->AddString("m");
     785               2 :           pktOut->AddNumberSep(curr, 0);
     786                 :         }
     787                 :         break;
     788                 :       }
     789                 : 
     790                 :       // Check for architecture query
     791             177 :       tmp = "Xfer:features:read:target.xml";
     792             177 :       if (!strncmp(str, tmp.data(), tmp.length())) {
     793              29 :         stringvec args = StringSplit(&str[tmp.length()+1], ",");
     794              29 :         if (args.size() != 2) break;
     795                 : 
     796              29 :         const char *out = properties_["target.xml"].data();
     797              29 :         int offs = strtol(args[0].data(), NULL, 16);
     798              29 :         int max  = strtol(args[1].data(), NULL, 16) + offs;
     799              29 :         int len  = static_cast<int>(strlen(out));
     800                 : 
     801              29 :         if (max >= len) max = len;
     802                 : 
     803            2088 :         while (offs < max) {
     804            2030 :           pktOut->AddRawChar(out[offs]);
     805            2030 :           offs++;
     806                 :         }
     807              29 :         break;
     808                 :       }
     809                 : 
     810                 :       // Check the property cache
     811             148 :       if (itr != properties_.end()) {
     812              29 :         pktOut->AddString(itr->second.data());
     813                 :       }
     814             180 :       break;
     815                 :     }
     816                 : 
     817                 :     case 's': {
     818               0 :       IThread *thread = GetRunThread();
     819               0 :       if (thread) thread->SetStep(true);
     820               0 :       return true;
     821                 :     }
     822                 : 
     823                 :     case 'T': {
     824                 :       uint64_t id;
     825               5 :       if (!pktIn->GetNumberSep(&id, 0)) {
     826               0 :         err = BAD_FORMAT;
     827               0 :         break;
     828                 :       }
     829                 : 
     830               5 :       if (GetThread(static_cast<uint32_t>(id)) == NULL) {
     831               0 :         err = BAD_ARGS;
     832               0 :         break;
     833                 :       }
     834                 : 
     835               5 :       pktOut->AddString("OK");
     836               5 :       break;
     837                 :     }
     838                 : 
     839                 :     case 'v': {
     840             160 :       const char *str = pktIn->GetPayload() + 1;
     841                 : 
     842             160 :       if (strncmp(str, "Cont", 4) == 0) {
     843                 :         // vCont
     844              84 :         const char *subcommand = str + 4;
     845                 : 
     846              84 :         if (strcmp(subcommand, "?") == 0) {
     847                 :           // Report supported vCont actions. These 4 are required.
     848              18 :           pktOut->AddString("vCont;s;S;c;C");
     849              18 :           break;
     850                 :         }
     851                 : 
     852              66 :         if (strcmp(subcommand, ";c") == 0) {
     853                 :           // Continue all threads.
     854              31 :           return true;
     855                 :         }
     856                 : 
     857              35 :         if (strncmp(subcommand, ";s:", 3) == 0) {
     858                 :           // Single step one thread and optionally continue all other threads.
     859                 :           char *end;
     860                 :           uint32_t thread_id = static_cast<uint32_t>(
     861              35 :               strtol(subcommand + 3, &end, 16));
     862              35 :           if (end == subcommand + 3) {
     863               0 :             err = BAD_ARGS;
     864               0 :             break;
     865                 :           }
     866                 : 
     867              35 :           ThreadMap_t::iterator it = threads_.find(thread_id);
     868              35 :           if (it == threads_.end()) {
     869               0 :             err = BAD_ARGS;
     870               0 :             break;
     871                 :           }
     872                 : 
     873              35 :           if (*end == 0) {
     874                 :             // Single step one thread and keep other threads stopped.
     875                 :             // GDB uses this to continue from a breakpoint, which works by:
     876                 :             // - replacing trap instruction with the original instruction;
     877                 :             // - single-stepping through the original instruction. Other threads
     878                 :             //   must remain stopped, otherwise they might execute the code at
     879                 :             //   the same address and thus miss the breakpoint;
     880                 :             // - replacing the original instruction with trap instruction;
     881                 :             // - continuing all threads;
     882              11 :             if (thread_id != sig_thread_) {
     883               0 :               err = BAD_ARGS;
     884               0 :               break;
     885                 :             }
     886              11 :             step_over_breakpoint_thread_ = sig_thread_;
     887              24 :           } else if (strcmp(end, ";c") == 0) {
     888                 :             // Single step one thread and continue all other threads.
     889                 :           } else {
     890                 :             // Unsupported combination of single step and other args.
     891               0 :             err = BAD_ARGS;
     892               0 :             break;
     893                 :           }
     894                 : 
     895              35 :           it->second->SetStep(true);
     896              35 :           return true;
     897                 :         }
     898                 : 
     899                 :         // Continue one thread and keep other threads stopped.
     900                 :         //
     901                 :         // GDB sends this for software single step, which is used:
     902                 :         // - on Win64 to step over rsp modification and subsequent rsp
     903                 :         //   sandboxing at once. For details, see:
     904                 :         //     http://code.google.com/p/nativeclient/issues/detail?id=2903
     905                 :         // - TODO: on ARM, which has no hardware support for single step
     906                 :         // - TODO: to step over syscalls
     907                 :         //
     908                 :         // Unfortunately, we can't make this just Win-specific. We might
     909                 :         // use Linux GDB to connect to Win debug stub, so even Linux GDB
     910                 :         // should send software single step. Vice versa, software single
     911                 :         // step-enabled Win GDB might be connected to Linux debug stub,
     912                 :         // so even Linux debug stub should accept software single step.
     913               0 :         if (strncmp(subcommand, ";c:", 3) == 0) {
     914                 :           char *end;
     915                 :           uint32_t thread_id = static_cast<uint32_t>(
     916               0 :               strtol(subcommand + 3, &end, 16));
     917               0 :           if (end != subcommand + 3 && *end == 0) {
     918               0 :             if (thread_id == sig_thread_) {
     919               0 :               step_over_breakpoint_thread_ = sig_thread_;
     920               0 :               return true;
     921                 :             }
     922                 :           }
     923                 : 
     924               0 :           err = BAD_ARGS;
     925               0 :           break;
     926                 :         }
     927                 : 
     928                 :         // Unsupported form of vCont.
     929               0 :         err = BAD_FORMAT;
     930               0 :         break;
     931              76 :       } else if (strncmp(str, "File:", 5) == 0) {
     932              76 :         ProcessFilePacket(pktIn, pktOut, &err);
     933              76 :         break;
     934                 :       }
     935                 : 
     936               0 :       NaClLog(LOG_ERROR, "Unknown command: %s\n", pktIn->GetPayload());
     937               0 :       return false;
     938                 :     }
     939                 : 
     940                 :     case 'Z': {
     941                 :       uint64_t breakpoint_type;
     942                 :       uint64_t breakpoint_address;
     943                 :       uint64_t breakpoint_kind;
     944             153 :       if (!pktIn->GetNumberSep(&breakpoint_type, 0) ||
     945                 :           breakpoint_type != 0 ||
     946              51 :           !pktIn->GetNumberSep(&breakpoint_address, 0) ||
     947              51 :           !pktIn->GetNumberSep(&breakpoint_kind, 0)) {
     948               0 :         err = BAD_FORMAT;
     949               0 :         break;
     950                 :       }
     951             102 :       if (breakpoint_address != (uint32_t) breakpoint_address ||
     952              51 :           !AddBreakpoint((uint32_t) breakpoint_address)) {
     953               1 :         err = FAILED;
     954               1 :         break;
     955                 :       }
     956              50 :       pktOut->AddString("OK");
     957              50 :       break;
     958                 :     }
     959                 : 
     960                 :     case 'z': {
     961                 :       uint64_t breakpoint_type;
     962                 :       uint64_t breakpoint_address;
     963                 :       uint64_t breakpoint_kind;
     964             150 :       if (!pktIn->GetNumberSep(&breakpoint_type, 0) ||
     965                 :           breakpoint_type != 0 ||
     966              50 :           !pktIn->GetNumberSep(&breakpoint_address, 0) ||
     967              50 :           !pktIn->GetNumberSep(&breakpoint_kind, 0)) {
     968               0 :         err = BAD_FORMAT;
     969               0 :         break;
     970                 :       }
     971             100 :       if (breakpoint_address != (uint32_t) breakpoint_address ||
     972              50 :           !RemoveBreakpoint((uint32_t) breakpoint_address)) {
     973               0 :         err = FAILED;
     974               0 :         break;
     975                 :       }
     976              50 :       pktOut->AddString("OK");
     977              50 :       break;
     978                 :     }
     979                 : 
     980                 :     default: {
     981                 :       // If the command is not recognzied, ignore it by sending an
     982                 :       // empty reply.
     983               8 :       string str;
     984               8 :       pktIn->GetString(&str);
     985               8 :       NaClLog(LOG_ERROR, "Unknown command: %s\n", pktIn->GetPayload());
     986               8 :       return false;
     987                 :     }
     988                 :   }
     989                 : 
     990                 :   // If there is an error, return the error code instead of a payload
     991             810 :   if (err) {
     992              61 :     pktOut->Clear();
     993              61 :     pktOut->AddRawChar('E');
     994              61 :     pktOut->AddWord8(err);
     995                 :   }
     996             810 :   return false;
     997                 : }
     998                 : 
     999                 : 
    1000              22 : void Target::TrackThread(struct NaClAppThread *natp) {
    1001                 :   // natp->thread_num values are 0-based indexes, but we treat 0 as
    1002                 :   // "not a thread ID", so we add 1.
    1003              22 :   uint32_t id = natp->thread_num + 1;
    1004              22 :   MutexLock lock(&mutex_);
    1005              22 :   CHECK(threads_[id] == 0);
    1006              22 :   threads_[id] = IThread::Create(id, natp);
    1007              22 : }
    1008                 : 
    1009               3 : void Target::IgnoreThread(struct NaClAppThread *natp) {
    1010               3 :   uint32_t id = natp->thread_num + 1;
    1011               3 :   MutexLock lock(&mutex_);
    1012               3 :   ThreadMap_t::iterator iter = threads_.find(id);
    1013               3 :   CHECK(iter != threads_.end());
    1014               3 :   delete iter->second;
    1015               3 :   threads_.erase(iter);
    1016               3 : }
    1017                 : 
    1018               3 : void Target::Exit() {
    1019               3 :   MutexLock lock(&mutex_);
    1020               3 :   if (session_ != NULL) {
    1021               1 :     Packet exit_packet;
    1022               1 :     if (NACL_ABI_WIFSIGNALED(nap_->exit_status)) {
    1023               0 :       exit_packet.AddRawChar('X');
    1024               0 :       exit_packet.AddWord8(NACL_ABI_WTERMSIG(nap_->exit_status));
    1025                 :     } else {
    1026               1 :       exit_packet.AddRawChar('W');
    1027               1 :       exit_packet.AddWord8(NACL_ABI_WEXITSTATUS(nap_->exit_status));
    1028                 :     }
    1029               1 :     session_->SendPacket(&exit_packet);
    1030               3 :   }
    1031               3 : }
    1032                 : 
    1033               2 : void Target::Detach() {
    1034               2 :   NaClLog(LOG_INFO, "Requested Detach.\n");
    1035               2 :   detaching_ = true;
    1036               2 : }
    1037                 : 
    1038              16 : void Target::Kill() {
    1039              16 :   NaClLog(LOG_INFO, "Requested Kill.\n");
    1040              16 :   should_exit_ = true;
    1041              16 : }
    1042                 : 
    1043             112 : IThread* Target::GetRegThread() {
    1044             112 :   ThreadMap_t::const_iterator itr;
    1045                 : 
    1046             112 :   switch (reg_thread_) {
    1047                 :     // If we want "any" then try the signal'd thread first
    1048                 :     case 0:
    1049                 :     case 0xFFFFFFFF:
    1050               0 :       itr = threads_.begin();
    1051               0 :       break;
    1052                 : 
    1053                 :     default:
    1054             112 :       itr = threads_.find(reg_thread_);
    1055             112 :       break;
    1056                 :   }
    1057                 : 
    1058             112 :   if (itr == threads_.end()) return 0;
    1059                 : 
    1060             112 :   return itr->second;
    1061                 : }
    1062                 : 
    1063               0 : IThread* Target::GetRunThread() {
    1064                 :   // This is used to select a thread for "s" (step) command only.
    1065                 :   // For multi-threaded targets, "s" is deprecated in favor of "vCont", which
    1066                 :   // always specifies the thread explicitly when needed. However, we want
    1067                 :   // to keep backward compatibility here, as using "s" when debugging
    1068                 :   // a single-threaded program might be a popular use case.
    1069               0 :   if (threads_.size() == 1) {
    1070               0 :     return threads_.begin()->second;
    1071                 :   }
    1072               0 :   return NULL;
    1073                 : }
    1074                 : 
    1075               5 : IThread* Target::GetThread(uint32_t id) {
    1076               5 :   ThreadMap_t::const_iterator itr;
    1077               5 :   itr = threads_.find(id);
    1078               5 :   if (itr != threads_.end()) return itr->second;
    1079                 : 
    1080               0 :   return NULL;
    1081                 : }
    1082                 : 
    1083              74 : void Target::SuspendAllThreads() {
    1084              74 :   NaClUntrustedThreadsSuspendAll(nap_, /* save_registers= */ 1);
    1085             312 :   for (ThreadMap_t::const_iterator iter = threads_.begin();
    1086             156 :        iter != threads_.end();
    1087                 :        ++iter) {
    1088              82 :     IThread *thread = iter->second;
    1089              82 :     thread->CopyRegistersFromAppThread();
    1090              82 :     CopyFaultSignalFromAppThread(thread);
    1091                 :   }
    1092              74 : }
    1093                 : 
    1094              57 : void Target::ResumeAllThreads() {
    1095             240 :   for (ThreadMap_t::const_iterator iter = threads_.begin();
    1096             120 :        iter != threads_.end();
    1097                 :        ++iter) {
    1098              63 :     iter->second->CopyRegistersToAppThread();
    1099                 :   }
    1100              57 :   NaClUntrustedThreadsResumeAll(nap_);
    1101              57 : }
    1102                 : 
    1103                 : // UnqueueAnyFaultedThread() picks a thread that has been blocked as a
    1104                 : // result of faulting and unblocks it.  It returns the thread's ID via
    1105                 : // |thread_id| and the type of fault via |signal|.  As a precondition,
    1106                 : // all threads must be currently suspended.
    1107              73 : void Target::UnqueueAnyFaultedThread(uint32_t *thread_id, int8_t *signal) {
    1108             160 :   for (ThreadMap_t::const_iterator iter = threads_.begin();
    1109              80 :        iter != threads_.end();
    1110                 :        ++iter) {
    1111              80 :     IThread *thread = iter->second;
    1112              80 :     if (thread->GetFaultSignal() != 0) {
    1113              73 :       *signal = thread->GetFaultSignal();
    1114              73 :       *thread_id = thread->GetId();
    1115              73 :       thread->UnqueueFaultedThread();
    1116             146 :       return;
    1117                 :     }
    1118                 :   }
    1119               0 :   NaClLog(LOG_FATAL, "UnqueueAnyFaultedThread: No threads queued\n");
    1120                 : }
    1121                 : 
    1122                 : }  // namespace gdb_rsp

Generated by: LCOV version 1.7