LCOV - code coverage report
Current view: directory - src/trusted/gdb_rsp - target.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 295 159 53.9 %
Date: 2012-02-16 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 "native_client/src/trusted/gdb_rsp/abi.h"
      12                 : #include "native_client/src/trusted/gdb_rsp/packet.h"
      13                 : #include "native_client/src/trusted/gdb_rsp/target.h"
      14                 : #include "native_client/src/trusted/gdb_rsp/session.h"
      15                 : #include "native_client/src/trusted/gdb_rsp/util.h"
      16                 : 
      17                 : #include "native_client/src/trusted/port/platform.h"
      18                 : #include "native_client/src/trusted/port/thread.h"
      19                 : 
      20                 : #ifdef WIN32
      21                 : #define snprintf sprintf_s
      22                 : #endif
      23                 : 
      24                 : using std::string;
      25                 : 
      26                 : using port::IEvent;
      27                 : using port::IMutex;
      28                 : using port::IPlatform;
      29                 : using port::IThread;
      30                 : using port::MutexLock;
      31                 : 
      32                 : namespace gdb_rsp {
      33                 : 
      34                 : 
      35               1 : Target::Target(const Abi* abi)
      36                 :   : abi_(abi),
      37                 :     mutex_(NULL),
      38                 :     sig_start_(NULL),
      39                 :     sig_done_(NULL),
      40                 :     send_done_(false),
      41                 :     ctx_(NULL),
      42                 :     cur_signal_(-1),
      43                 :     sig_thread_(0),
      44                 :     run_thread_(-1),
      45                 :     reg_thread_(-1),
      46               1 :     mem_base_(0) {
      47               1 :   if (NULL == abi_) abi_ = Abi::Get();
      48               1 : }
      49                 : 
      50               1 : Target::~Target() {
      51               1 :   Destroy();
      52               1 : }
      53                 : 
      54               1 : bool Target::Init() {
      55               1 :   string targ_xml = "l<target><architecture>";
      56                 : 
      57               2 :   targ_xml += abi_->GetName();
      58               1 :   targ_xml += "</architecture></target>";
      59                 : 
      60                 :   // Set a more specific result which won't change.
      61               1 :   properties_["target.xml"] = targ_xml;
      62                 :   properties_["Supported"] =
      63               2 :     "PacketSize=7cf;qXfer:libraries:read+;qXfer:features:read+";
      64                 : 
      65               2 :   mutex_ = IMutex::Allocate();
      66               1 :   sig_start_ = IEvent::Allocate();
      67               1 :   sig_done_ = IEvent::Allocate();
      68               1 :   ctx_ = new uint8_t[abi_->GetContextSize()];
      69                 : 
      70               1 :   if ((NULL == mutex_) || (NULL == sig_start_) || (NULL == sig_done_)
      71                 :       || (NULL == ctx_)) {
      72               0 :     Destroy();
      73               0 :     return false;
      74                 :   }
      75                 : 
      76                 :   // Allow one exception to happen
      77               1 :   sig_start_->Signal();
      78               1 :   return true;
      79                 : }
      80                 : 
      81               1 : void Target::Destroy() {
      82               1 :   if (mutex_) IMutex::Free(mutex_);
      83               1 :   if (sig_start_) IEvent::Free(sig_start_);
      84               1 :   if (sig_done_) IEvent::Free(sig_done_);
      85                 : 
      86               1 :   delete[] ctx_;
      87               1 : }
      88                 : 
      89               0 : bool Target::AddTemporaryBreakpoint(uint64_t address) {
      90               0 :   const Abi::BPDef *bp = abi_->GetBreakpointDef();
      91                 : 
      92                 :   // If this ABI does not support breakpoints then fail
      93               0 :   if (NULL == bp) return false;
      94                 : 
      95                 :   // If we alreay have a breakpoint here then don't add it
      96               0 :   BreakMap_t::iterator itr = breakMap_.find(address);
      97               0 :   if (itr != breakMap_.end()) return false;
      98                 : 
      99               0 :   uint8_t *data = new uint8_t[bp->size_];
     100               0 :   if (NULL == data) return false;
     101                 : 
     102                 :   // Copy the old code from here
     103               0 :   if (IPlatform::GetMemory(address, bp->size_, data) == false) {
     104               0 :     delete[] data;
     105               0 :     return false;
     106                 :   }
     107               0 :   if (IPlatform::SetMemory(address, bp->size_, bp->code_) == false) {
     108               0 :     delete[] data;
     109               0 :     return false;
     110                 :   }
     111                 : 
     112               0 :   breakMap_[address] = data;
     113               0 :   return true;
     114                 : }
     115                 : 
     116               1 : bool Target::RemoveTemporaryBreakpoints() {
     117               1 :   const Abi::BPDef *bp = abi_->GetBreakpointDef();
     118                 : 
     119                 :   // Iterate through the map, removing breakpoints
     120               2 :   while (!breakMap_.empty()) {
     121                 :     // Copy the key/value locally
     122               0 :     BreakMap_t::iterator cur = breakMap_.begin();
     123               0 :     uint64_t addr = cur->first;
     124               0 :     uint8_t *data = cur->second;
     125                 : 
     126                 :     // Then remove it from the map
     127               0 :     breakMap_.erase(cur);
     128                 : 
     129                 :     // Copy back the old code, and free the data
     130               0 :     if (!IPlatform::SetMemory(addr, bp->size_, data))
     131               0 :       port::IPlatform::LogError("Failed to undo breakpoint.\n");
     132               0 :     delete[] data;
     133                 :   }
     134                 : 
     135               1 :   return true;
     136                 : }
     137                 : 
     138                 : 
     139                 : 
     140               1 : void Target::Signal(uint32_t id, int8_t sig, bool wait) {
     141                 :   // Wait for this signal's turn in the signal Q.
     142               1 :   sig_start_->Wait();
     143                 :   {
     144                 :     // Now lock the target, sleeping all active threads
     145               1 :     MutexLock lock(mutex_);
     146                 : 
     147                 :     // Suspend all threads except this one
     148                 :     uint32_t curId;
     149               1 :     bool more = GetFirstThreadId(&curId);
     150               3 :     while (more) {
     151               1 :       if (curId != id) {
     152               0 :         IThread *thread = threads_[curId];
     153               0 :         thread->Suspend();
     154                 :       }
     155               1 :       more = GetNextThreadId(&curId);
     156                 :     }
     157                 : 
     158                 :     // Signal the stub (Run thread) that we are ready to process
     159                 :     // a trap, by updating the signal information and releasing
     160                 :     // the lock.
     161               1 :     reg_thread_ = id;
     162               1 :     run_thread_ = id;
     163               1 :     cur_signal_ = sig;
     164                 :   }
     165                 : 
     166                 :   // Wait for permission to continue
     167               1 :   if (wait) sig_done_->Wait();
     168               1 : }
     169                 : 
     170               1 : void Target::Run(Session *ses) {
     171               1 :   bool first = true;
     172               1 :   do {
     173                 :     // Give everyone else a chance to use the lock
     174               1 :     IPlatform::Relinquish(100);
     175                 : 
     176                 :     // Lock to prevent anyone else from modifying threads
     177                 :     // or updating the signal information.
     178               1 :     MutexLock lock(mutex_);
     179               1 :     Packet recv, reply;
     180                 : 
     181               1 :     uint32_t id = 0;
     182                 : 
     183                 :     // If no signal is waiting for this iteration...
     184               1 :     if (-1 == cur_signal_) {
     185                 :       // but the debugger is talking to us then force a break
     186               0 :       if (ses->DataAvailable()) {
     187                 :         // set signal to 0 to signify paused
     188               0 :         cur_signal_ = 0;
     189                 : 
     190                 :         // put all the threads to sleep.
     191                 :         uint32_t curId;
     192               0 :         bool more = GetFirstThreadId(&curId);
     193               0 :         while (more) {
     194               0 :           if (curId != id) {
     195               0 :             IThread *thread = threads_[curId];
     196               0 :             thread->Suspend();
     197                 :           }
     198               0 :           more = GetNextThreadId(&curId);
     199                 :         }
     200                 :       } else {
     201                 :         // otherwise, nothing to do so try again.
     202               0 :         continue;
     203                 :       }
     204                 :     } else {
     205                 :       // otherwise there really is an exception so get the id of the thread
     206               1 :       id = GetRegThreadId();
     207                 :     }
     208                 : 
     209                 :     // If we got this far, then there is some kind of signal.
     210                 :     // So first, remove the breakpoints
     211               1 :     RemoveTemporaryBreakpoints();
     212                 : 
     213                 :     // Next update the current thread info
     214                 :     char tmp[16];
     215               1 :     snprintf(tmp, sizeof(tmp), "QC%x", id);
     216               1 :     properties_["C"] = tmp;
     217                 : 
     218               1 :     if (first) {
     219                 :       // First time on a connection, we don't sent the signal
     220               1 :       first = false;
     221                 :     } else {
     222                 :       // All other times, send the signal that triggered us
     223               0 :       Packet pktOut;
     224               0 :       pktOut.AddRawChar('S');
     225               0 :       pktOut.AddWord8(cur_signal_);
     226               0 :       ses->SendPacketOnly(&pktOut);
     227                 :     }
     228                 : 
     229                 :     // Now we are ready to process commands
     230                 :     // Loop through packets until we process a continue
     231                 :     // packet.
     232               8 :     do {
     233               8 :       if (ses->GetPacket(&recv)) {
     234               7 :         reply.Clear();
     235               7 :         if (ProcessPacket(&recv, &reply)) {
     236                 :           // If this is a continue command, break out of this loop
     237               0 :           break;
     238                 :         } else {
     239                 :           // Othwerise send the reponse
     240               7 :           ses->SendPacket(&reply);
     241                 :         }
     242                 :       }
     243                 :     } while (ses->Connected());
     244                 : 
     245                 : 
     246                 :     // Now that we are done, we want to continue in the "correct order".
     247                 :     // This means letting the active thread go first, in case we are single
     248                 :     // stepping and want to catch it again.  This is a desired behavior but
     249                 :     // it is not guaranteed since another thread may already be in an
     250                 :     // exception state and next in line to notify the target.
     251                 : 
     252                 :     // If the run thread is not the exception thread, wake it up now.
     253               1 :     uint32_t run_thread = GetRunThreadId();
     254               1 :     if (run_thread != id
     255                 :         && run_thread != static_cast<uint32_t>(-1)) {
     256               0 :       IThread* thread = threads_[run_thread];
     257               0 :       thread->Resume();
     258                 :     }
     259                 : 
     260                 :     // Next, wake up the exception thread, if there is one and it needs
     261                 :     // to wake up.
     262               1 :     if (id && send_done_) sig_done_->Signal();
     263                 : 
     264                 :     // Now wake up everyone else
     265                 :     uint32_t curId;
     266               1 :     bool more = GetFirstThreadId(&curId);
     267               3 :     while (more) {
     268               1 :       if ((curId != id) && (curId != GetRunThreadId())) {
     269               0 :         IThread *thread = threads_[curId];
     270               0 :         thread->Resume();
     271                 :       }
     272               1 :       more = GetNextThreadId(&curId);
     273                 :     }
     274                 : 
     275                 :     // Reset the signal value
     276               1 :     cur_signal_ = -1;
     277                 : 
     278                 :     // If we took an exception, let the handler resume and allow
     279                 :     // the next exception to come in.
     280               1 :     if (cur_signal_) {
     281               1 :       sig_done_->Signal();
     282               1 :       sig_start_->Signal();
     283               0 :     }
     284                 : 
     285                 :     // Continue running until the connection is lost.
     286                 :   } while (ses->Connected());
     287               1 : }
     288                 : 
     289                 : 
     290                 : 
     291                 : 
     292               3 : bool Target::GetFirstThreadId(uint32_t *id) {
     293               3 :   threadItr_ = threads_.begin();
     294               3 :   return GetNextThreadId(id);
     295                 : }
     296                 : 
     297               6 : bool Target::GetNextThreadId(uint32_t *id) {
     298               6 :   if (threadItr_ == threads_.end()) return false;
     299                 : 
     300               3 :   *id = (*threadItr_).first;
     301               3 :   threadItr_++;
     302                 : 
     303               3 :   return true;
     304                 : }
     305                 : 
     306                 : 
     307                 : 
     308               7 : bool Target::ProcessPacket(Packet* pktIn, Packet* pktOut) {
     309                 :   char cmd;
     310               7 :   int32_t seq = -1;
     311               7 :   ErrDef  err = NONE;
     312                 : 
     313                 :   // Clear the outbound message
     314               7 :   pktOut->Clear();
     315                 : 
     316                 :   // Pull out the sequence.
     317               7 :   pktIn->GetSequence(&seq);
     318               7 :   if (seq != -1) pktOut->SetSequence(seq);
     319                 : 
     320                 :   // Find the command
     321               7 :   pktIn->GetRawChar(&cmd);
     322                 : 
     323               7 :   switch (cmd) {
     324                 :     // IN : $?
     325                 :     // OUT: $Sxx
     326                 :     case '?':
     327               1 :       pktOut->AddRawChar('S');
     328               1 :       pktOut->AddWord8(cur_signal_);
     329               1 :       break;
     330                 : 
     331                 :     // IN : $d
     332                 :     // OUT: -NONE-
     333                 :     case 'd':
     334               0 :       Detach();
     335               0 :       break;
     336                 : 
     337                 :     // IN : $g
     338                 :     // OUT: $xx...xx
     339                 :     case 'g': {
     340               1 :       uint32_t id = GetRegThreadId();
     341               1 :       if (0 == id) {
     342               0 :         err = BAD_ARGS;
     343               0 :         break;
     344                 :       }
     345                 : 
     346               1 :       IThread *thread = GetThread(id);
     347               1 :       if (NULL == thread) {
     348               0 :         err = BAD_ARGS;
     349               0 :         break;
     350                 :       }
     351                 : 
     352                 :       // Copy OS preserved registers to GDB payload
     353              17 :       for (uint32_t a = 0; a < abi_->GetRegisterCount(); a++) {
     354              16 :         const Abi::RegDef *def = abi_->GetRegisterDef(a);
     355              16 :         thread->GetRegister(a, &ctx_[def->offset_], def->bytes_);
     356                 :       }
     357                 : 
     358               1 :       pktOut->AddBlock(ctx_, abi_->GetContextSize());
     359               1 :       break;
     360                 :     }
     361                 : 
     362                 :     // IN : $Gxx..xx
     363                 :     // OUT: $OK
     364                 :     case 'G': {
     365               0 :       uint32_t id = GetRegThreadId();
     366               0 :       if (0 == id) {
     367               0 :         err = BAD_ARGS;
     368               0 :         break;
     369                 :       }
     370                 : 
     371               0 :       IThread *thread = threads_[id];
     372               0 :       if (NULL == thread) {
     373               0 :         err = BAD_ARGS;
     374               0 :         break;
     375                 :       }
     376                 : 
     377                 :       // GDB payload to OS registers
     378               0 :       for (uint32_t a = 0; a < abi_->GetRegisterCount(); a++) {
     379               0 :         const Abi::RegDef *def = abi_->GetRegisterDef(a);
     380               0 :         thread->SetRegister(a, &ctx_[def->offset_], def->bytes_);
     381                 :       }
     382               0 :       pktOut->AddBlock(ctx_, abi_->GetContextSize());
     383               0 :       break;
     384                 :     }
     385                 : 
     386                 :     // IN : $H(c/g)(-1,0,xxxx)
     387                 :     // OUT: $OK
     388                 :     case 'H': {
     389                 :         char type;
     390                 :         uint64_t id;
     391                 : 
     392               1 :         if (!pktIn->GetRawChar(&type)) {
     393               0 :           err = BAD_FORMAT;
     394               0 :           break;
     395                 :         }
     396               1 :         if (!pktIn->GetNumberSep(&id, 0)) {
     397               0 :           err = BAD_FORMAT;
     398               0 :           break;
     399                 :         }
     400                 : 
     401               1 :         if (threads_.begin() == threads_.end()) {
     402               0 :             err = BAD_ARGS;
     403               0 :             break;
     404                 :         }
     405                 : 
     406                 :         // If we are using "any" get the first thread
     407               1 :         if (id == static_cast<uint64_t>(-1)) id = threads_.begin()->first;
     408                 : 
     409                 :         // Verify that we have the thread
     410               1 :         if (threads_.find(static_cast<uint32_t>(id)) == threads_.end()) {
     411               0 :           err = BAD_ARGS;
     412               0 :           break;
     413                 :         }
     414                 : 
     415               1 :         pktOut->AddString("OK");
     416               1 :         switch (type) {
     417                 :           case 'g':
     418               1 :             reg_thread_ = static_cast<uint32_t>(id);
     419               1 :             break;
     420                 : 
     421                 :           case 'c':
     422               0 :             run_thread_ = static_cast<uint32_t>(id);
     423               0 :             break;
     424                 : 
     425                 :           default:
     426               0 :             err = BAD_ARGS;
     427                 :             break;
     428                 :         }
     429               1 :         break;
     430                 :       }
     431                 : 
     432                 :     // IN : $maaaa,llll
     433                 :     // OUT: $xx..xx
     434                 :     case 'm': {
     435                 :         uint64_t addr;
     436                 :         uint64_t wlen;
     437                 :         uint32_t len;
     438               0 :         if (!pktIn->GetNumberSep(&addr, 0)) {
     439               0 :           err = BAD_FORMAT;
     440               0 :           break;
     441                 :         }
     442               0 :         if (addr < mem_base_) {
     443               0 :           addr += mem_base_;
     444                 :         }
     445               0 :         if (!pktIn->GetNumberSep(&wlen, 0)) {
     446               0 :           err = BAD_FORMAT;
     447               0 :           break;
     448                 :         }
     449                 : 
     450               0 :         len = static_cast<uint32_t>(wlen);
     451               0 :         uint8_t *block = new uint8_t[len];
     452               0 :         if (!port::IPlatform::GetMemory(addr, len, block)) err = FAILED;
     453                 : 
     454               0 :         pktOut->AddBlock(block, len);
     455               0 :         break;
     456                 :       }
     457                 : 
     458                 :     // IN : $Maaaa,llll:xx..xx
     459                 :     // OUT: $OK
     460                 :     case 'M':  {
     461                 :         uint64_t addr;
     462                 :         uint64_t wlen;
     463                 :         uint32_t len;
     464                 : 
     465               0 :         if (!pktIn->GetNumberSep(&addr, 0)) {
     466               0 :           err = BAD_FORMAT;
     467               0 :           break;
     468                 :         }
     469               0 :         if (addr < mem_base_) {
     470               0 :           addr += mem_base_;
     471                 :         }
     472                 : 
     473               0 :         if (!pktIn->GetNumberSep(&wlen, 0)) {
     474               0 :           err = BAD_FORMAT;
     475               0 :           break;
     476                 :         }
     477                 : 
     478               0 :         len = static_cast<uint32_t>(wlen);
     479               0 :         uint8_t *block = new uint8_t[len];
     480               0 :         pktIn->GetBlock(block, len);
     481                 : 
     482               0 :         if (!port::IPlatform::SetMemory(addr, len, block)) err = FAILED;
     483                 : 
     484               0 :         pktOut->AddString("OK");
     485               0 :         break;
     486                 :       }
     487                 : 
     488                 :     case 'q': {
     489               4 :       string tmp;
     490               4 :       const char *str = &pktIn->GetPayload()[1];
     491               4 :       stringvec toks = StringSplit(str, ":;");
     492               8 :       PropertyMap_t::const_iterator itr = properties_.find(toks[0]);
     493                 : 
     494                 :       // If this is a thread query
     495               4 :       if (!strcmp(str, "fThreadInfo") || !strcmp(str, "sThreadInfo")) {
     496                 :         uint32_t curr;
     497               2 :         bool more = false;
     498               2 :         if (str[0] == 'f') {
     499               1 :           more = GetFirstThreadId(&curr);
     500                 :         } else {
     501               1 :           more = GetNextThreadId(&curr);
     502                 :         }
     503                 : 
     504               2 :         if (!more) {
     505               1 :           pktOut->AddString("l");
     506                 :         } else {
     507               1 :           pktOut->AddString("m");
     508               1 :           pktOut->AddNumberSep(curr, 0);
     509                 :         }
     510               4 :         break;
     511                 :       }
     512                 : 
     513                 :       // Check for architecture query
     514               2 :       tmp = "Xfer:features:read:target.xml";
     515               2 :       if (!strncmp(str, tmp.data(), tmp.length())) {
     516               1 :         stringvec args = StringSplit(&str[tmp.length()+1], ",");
     517               1 :         if (args.size() != 2) break;
     518                 : 
     519               1 :         const char *out = properties_["target.xml"].data();
     520               2 :         int offs = strtol(args[0].data(), NULL, 16);
     521               1 :         int max  = strtol(args[1].data(), NULL, 16) + offs;
     522               1 :         int len  = static_cast<int>(strlen(out));
     523                 : 
     524               1 :         if (max >= len) max = len;
     525                 : 
     526              53 :         while (offs < max) {
     527              51 :           pktOut->AddRawChar(out[offs]);
     528              51 :           offs++;
     529                 :         }
     530               0 :         break;
     531                 :       }
     532                 : 
     533                 :       // Check the property cache
     534               1 :       if (itr != properties_.end()) {
     535               1 :         pktOut->AddString(itr->second.data());
     536                 :       }
     537               0 :       break;
     538                 :     }
     539                 : 
     540                 :     case 'T': {
     541                 :       uint64_t id;
     542               0 :       if (!pktIn->GetNumberSep(&id, 0)) {
     543               0 :         err = BAD_FORMAT;
     544               0 :         break;
     545                 :       }
     546                 : 
     547               0 :       if (GetThread(static_cast<uint32_t>(id)) == NULL) {
     548               0 :         err = BAD_ARGS;
     549               0 :         break;
     550                 :       }
     551                 : 
     552               0 :       pktOut->AddString("OK");
     553               0 :       break;
     554                 :     }
     555                 : 
     556                 :     case 's':  {
     557               0 :       IThread *thread = GetThread(GetRunThreadId());
     558               0 :       if (thread) thread->SetStep(true);
     559               0 :       return true;
     560                 :     }
     561                 : 
     562                 :     case 'c':
     563               0 :       return true;
     564                 : 
     565                 :     default: {
     566                 :       // If the command is not recognzied, ignore it by sending an
     567                 :       // empty reply.
     568               0 :       string str;
     569               0 :       pktIn->GetString(&str);
     570               0 :       port::IPlatform::LogError("Unknown command: %s\n", str.data());
     571               0 :       return false;
     572                 :     }
     573                 :   }
     574                 : 
     575                 :   // If there is an error, return the error code instead of a payload
     576               7 :   if (err) {
     577               0 :     pktOut->Clear();
     578               0 :     pktOut->AddRawChar('E');
     579               0 :     pktOut->AddWord8(err);
     580                 :   }
     581               7 :   return false;
     582                 : }
     583                 : 
     584                 : 
     585               1 : void Target::TrackThread(IThread* thread) {
     586               1 :   uint32_t id = thread->GetId();
     587               1 :   mutex_->Lock();
     588               1 :   threads_[id] = thread;
     589               1 :   mutex_->Unlock();
     590               1 : }
     591                 : 
     592               0 : void Target::IgnoreThread(IThread* thread) {
     593               0 :   uint32_t id = thread->GetId();
     594               0 :   mutex_->Lock();
     595               0 :   ThreadMap_t::iterator itr = threads_.find(id);
     596                 : 
     597               0 :   if (itr != threads_.end()) threads_.erase(itr);
     598               0 :   mutex_->Unlock();
     599               0 : }
     600                 : 
     601                 : 
     602               0 : void Target::Detach() {
     603               0 :   port::IPlatform::LogInfo("Requested Detach.\n");
     604               0 : }
     605                 : 
     606                 : 
     607               2 : uint32_t Target::GetRegThreadId() const {
     608               2 :   ThreadMap_t::const_iterator itr;
     609                 : 
     610               2 :   switch (reg_thread_) {
     611                 :     // If we wany "any" then try the signal'd thread first
     612                 :     case 0:
     613                 :     case 0xFFFFFFFF:
     614               0 :       itr = threads_.begin();
     615               0 :       break;
     616                 : 
     617                 :     default:
     618               2 :       itr = threads_.find(reg_thread_);
     619                 :       break;
     620                 :   }
     621                 : 
     622               2 :   if (itr == threads_.end()) return 0;
     623                 : 
     624               2 :   return itr->first;
     625                 : }
     626                 : 
     627               1 : uint32_t Target::GetRunThreadId() const {
     628               1 :   return run_thread_;
     629                 : }
     630                 : 
     631               1 : IThread* Target::GetThread(uint32_t id) {
     632               1 :   ThreadMap_t::const_iterator itr;
     633               1 :   itr = threads_.find(id);
     634               1 :   if (itr != threads_.end()) return itr->second;
     635                 : 
     636               0 :   return NULL;
     637                 : }
     638                 : 
     639                 : 
     640                 : }  // namespace gdb_rsp
     641                 : 
     642                 : 
     643                 : 
     644                 : 

Generated by: LCOV version 1.7