LCOV - code coverage report
Current view: directory - src/trusted/gdb_rsp - host.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 261 147 56.3 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright 2010 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can
       4                 :  * be found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : #include <assert.h>
       8                 : #include <string.h>
       9                 : #include <stdlib.h>
      10                 : #include <stdio.h>
      11                 : 
      12                 : #include "native_client/src/trusted/gdb_rsp/abi.h"
      13                 : #include "native_client/src/trusted/gdb_rsp/host.h"
      14                 : #include "native_client/src/trusted/gdb_rsp/packet.h"
      15                 : #include "native_client/src/trusted/gdb_rsp/session.h"
      16                 : #include "native_client/src/trusted/gdb_rsp/util.h"
      17                 : 
      18                 : #include "native_client/src/trusted/port/std_types.h"
      19                 : #include "native_client/src/trusted/port/platform.h"
      20                 : 
      21                 : #ifdef WIN32
      22                 : #define snprintf sprintf_s
      23                 : #endif
      24                 : 
      25                 : 
      26                 : using std::string;
      27                 : using port::IPlatform;
      28                 : 
      29                 : namespace gdb_rsp {
      30                 : 
      31               1 : Host::Thread::Thread(const Abi *abi, uint32_t id)
      32               1 :   : id_(id), ctx_(NULL), abi_(abi) {
      33               1 :   ctx_ = new uint8_t[abi_->GetContextSize()];
      34               1 :   assert(NULL != ctx_);
      35               1 : }
      36                 : 
      37               0 : Host::Thread::~Thread() {
      38               0 :   delete[] ctx_;
      39               0 : }
      40                 : 
      41               0 : uint32_t Host::Thread::GetId() const {
      42               0 :   return id_;
      43                 : }
      44                 : 
      45               0 : const Abi *Host::Thread::GetAbi() const {
      46               0 :   return abi_;
      47                 : }
      48                 : 
      49              16 : void Host::Thread::GetRegister(uint32_t index, void *dst) const {
      50              16 :   assert(NULL != dst);
      51              16 :   assert(index < abi_->GetRegisterCount());
      52                 : 
      53              16 :   const Abi::RegDef *def = abi_->GetRegisterDef(index);
      54              16 :   uint8_t *ptr = ctx_ + def->offset_;
      55              16 :   memcpy(dst, ptr, def->bytes_);
      56              16 : }
      57                 : 
      58               0 : void Host::Thread::SetRegister(uint32_t index, const void *src) {
      59               0 :   assert(src);
      60               0 :   assert(index < abi_->GetRegisterCount());
      61                 : 
      62               0 :   const Abi::RegDef *def = abi_->GetRegisterDef(index);
      63               0 :   uint8_t *ptr = ctx_ + def->offset_;
      64               0 :   memcpy(ptr, src, def->bytes_);
      65               0 : }
      66                 : 
      67                 : 
      68                 : // Construct unitialzied
      69               1 : Host::Host(Session *session) : session_(session), abi_(NULL),
      70               1 :                                status_(HS_UNINIT) { }
      71                 : 
      72               1 : Host::~Host() { }
      73                 : 
      74               1 : bool Host::Init() {
      75               1 :   string reply;
      76                 : 
      77               1 :   properties_.clear();
      78                 : 
      79                 :   // Set the default max packet size.  We use the default value
      80                 :   // that GDB appears to like which is 1K - xsum/etc overhead.
      81               1 :   properties_["PacketSize"] = "3fa";
      82                 : 
      83                 :   // Get properties
      84               2 :   if (!Request("qSupported", &reply)) return false;
      85                 : 
      86                 :   // Parse the semicolon delimited properties
      87               1 :   stringvec tokens = StringSplit(reply.data(), ";");
      88               4 :   for (uint32_t loop = 0; loop < tokens.size(); loop++) {
      89                 :     // Properties are in the form of "Key=Val", "Key+", or "Key-"
      90               3 :     string &prop = tokens[loop];
      91                 : 
      92                 :     // If the form is Key=Val, there should be two components Key and Val
      93               3 :     stringvec keyval = StringSplit(prop, "=");
      94               3 :     if (keyval.size() == 2) {
      95               1 :       properties_[keyval[0]] = keyval[1];
      96               3 :       continue;
      97                 :     }
      98                 : 
      99                 :     // Strip off the + or - by splitting to get the name.
     100               2 :     keyval = StringSplit(prop, "+-");
     101                 :     // Size==1 means we got either XXX, XXX+, or XXX-
     102               2 :     if (keyval.size() == 1) {
     103               2 :       size_t len = prop.length();
     104                 :       // In which case the last character must be + or -, or we ignore.
     105               2 :       switch (prop[len - 1]) {
     106                 :         case '+' :
     107               2 :           properties_[keyval[0]] = "true";
     108                 :           continue;
     109                 :         case '-' :
     110               0 :           properties_[keyval[0]] = "false";
     111                 :           continue;
     112                 :       }
     113                 :     }
     114                 : 
     115                 :     // Otherwise it was a malformed property
     116                 :     IPlatform::LogError("Returned feature with strange assignment: %s",
     117               0 :                         prop.data());
     118                 :   }
     119                 : 
     120                 :   // Must support and use property read method to get CPU type
     121               1 :   if (!ReadObject("features", "target.xml", &reply)) return false;
     122                 : 
     123                 :   // Search for start of "architecture" tag
     124               1 :   const char *name = strstr(reply.data(), "<architecture>");
     125               1 :   if (NULL != name) {
     126                 :     // Size of "<architecture>"
     127               1 :     const int nameStart = 14;
     128               1 :     char *str = strdup(&name[nameStart]);
     129               1 :     char *term = strchr(str, '<');
     130               1 :     *term = 0;
     131                 : 
     132               1 :     abi_ = Abi::Find(str);
     133               1 :     free(str);
     134                 :   }
     135                 : 
     136                 :   // Check if we failed to find the correct ABI
     137               1 :   if (NULL == abi_) {
     138               0 :     IPlatform::LogError("Failed to find ABI for %s\n", reply.data());
     139               0 :     return false;
     140                 :   }
     141                 : 
     142               1 :   return Update();
     143                 : }
     144                 : 
     145               2 : bool Host::Update() {
     146               2 :   ThreadVector_t old_ids;
     147               4 :   ThreadVector_t new_ids;
     148                 : 
     149               4 :   ThreadMap_t::const_iterator itr = threads_.begin();
     150               5 :   while (itr != threads_.end()) {
     151               1 :     old_ids.push_back(itr->first);
     152               1 :     itr++;
     153                 :   }
     154                 : 
     155               2 :   if (!RequestThreadList(&new_ids)) return false;
     156                 : 
     157               4 :   for (uint32_t loop = 0; loop < new_ids.size(); loop++) {
     158                 :     // Large enough for log10(2^32) + NUL + "Hg";
     159                 :     char tmp[16];
     160                 : 
     161               2 :     uint32_t id = new_ids[loop];
     162               2 :     string request;
     163               2 :     string ignore_reply;
     164                 : 
     165               2 :     snprintf(tmp, sizeof(tmp), "Hg%x", id);
     166               2 :     if (!Request(tmp, &ignore_reply)) {
     167               0 :       IPlatform::LogError("Failed to set thread context for %d.\n", id);
     168               0 :       continue;
     169                 :     }
     170                 : 
     171               2 :     Packet req, resp;
     172               2 :     req.AddString("g");
     173               2 :     if (!Send(&req, &resp)) {
     174               0 :       IPlatform::LogError("Failed to get thread registers for %d.\n", id);
     175                 :       continue;
     176                 :     }
     177                 : 
     178               2 :     Thread *thread = threads_[id];
     179               2 :     if (NULL == thread) {
     180               1 :       thread = new Thread(abi_, id);
     181               2 :       threads_[id] = thread;
     182                 :     }
     183                 : 
     184               2 :     resp.GetBlock(thread->ctx_, abi_->GetContextSize());
     185                 :   }
     186                 : 
     187                 :   // Update the current state
     188               2 :   string reply;
     189               2 :   if (Request("?", &reply)) return ParseStopPacket(reply.data());
     190                 : 
     191                 :   // If we are not "broken" then we must have failed to update
     192               0 :   return false;
     193                 : }
     194                 : 
     195               0 : bool Host::GetThreads(ThreadVector_t* threads) const {
     196                 :   // We can get threads if stopped
     197               0 :   if (HS_STOPPED != status_) return false;
     198                 : 
     199               0 :   threads->clear();
     200               0 :   ThreadMap_t::const_iterator itr  = threads_.begin();
     201               0 :   while (itr != threads_.end()) {
     202               0 :     threads->push_back(itr->first);
     203               0 :     itr++;
     204                 :   }
     205                 : 
     206               0 :   return true;
     207                 : }
     208                 : 
     209               0 : bool Host::Step() {
     210               0 :   Packet out;
     211                 : 
     212                 :   // We can only step if we are stopped
     213               0 :   if (HS_STOPPED != status_) return false;
     214                 : 
     215               0 :   out.AddRawChar('s');
     216               0 :   if (SendOnly(&out)) {
     217                 :     // We are running again (even if we expect to immediately break)
     218               0 :     status_ = HS_RUNNING;
     219               0 :     return true;
     220                 :   }
     221                 : 
     222               0 :   return false;
     223                 : }
     224                 : 
     225               1 : bool Host::Continue() {
     226               1 :   Packet out;
     227                 : 
     228                 :   // We can only step if we are stopped
     229               1 :   if (HS_STOPPED != status_) return false;
     230                 : 
     231               1 :   out.AddRawChar('c');
     232               1 :   if (SendOnly(&out)) {
     233                 :     // We are running again
     234               1 :     status_ = HS_RUNNING;
     235               1 :     return true;
     236                 :   }
     237                 : 
     238               0 :   return false;
     239                 : }
     240                 : 
     241                 : // Wait to see if we receive a break
     242               2 : bool Host::WaitForBreak() {
     243                 :   // We can not wait if we are not running
     244               2 :   if (HS_RUNNING != status_) return false;
     245                 : 
     246               2 :   Packet rx;
     247               2 :   std::string str;
     248               2 :   if (session_->GetPacket(&rx) == false) return false;
     249                 : 
     250               1 :   rx.GetString(&str);
     251               3 :   if (ParseStopPacket(str.data())) return Update();
     252               0 :   return false;
     253                 : }
     254                 : 
     255                 : 
     256                 : 
     257               1 : Host::Thread* Host::GetThread(uint32_t id) {
     258               1 :   ThreadMap_t::const_iterator itr;
     259               1 :   itr = threads_.find(id);
     260                 : 
     261               1 :   if (itr == threads_.end()) return NULL;
     262                 : 
     263               1 :   return itr->second;
     264                 : }
     265                 : 
     266               3 : bool Host::ParseStopPacket(const char *data) {
     267               3 :   if (strlen(data) < 3) return false;
     268                 : 
     269                 :   // Stop in the form of (S|T|W|X)[XX]{n=xxx,r=yyy;{...}}
     270                 :   // where XX is the result code (Unix signal number for stops)
     271                 :   // or the form of OXX{XX..} where XX is a hex pair encoded string.
     272               3 :   switch (data[0]) {
     273                 :     // Both S & T signals are a normal stop
     274                 :     case 'S':
     275                 :     case 'T':
     276               3 :       status_ = HS_STOPPED;
     277               3 :       break;
     278                 : 
     279                 :     case 'W':
     280               0 :       status_ = HS_EXIT;
     281               0 :       break;
     282                 : 
     283                 :     case 'X':
     284               0 :       status_ = HS_TERMINATED;
     285               0 :       break;
     286                 : 
     287                 :     case 'O':
     288               0 :       return true;
     289                 : 
     290                 :     default:
     291               0 :       return false;
     292                 :   }
     293                 : 
     294               3 :   if (!NibblesToByte(&data[1], &lastSignal_)) return false;
     295                 : 
     296               3 :   return true;
     297                 : }
     298                 : 
     299                 : 
     300               2 : bool Host::RequestThreadList(ThreadVector_t* ids) {
     301               2 :   string reply;
     302                 : 
     303               2 :   ids->clear();
     304                 : 
     305               2 :   if (!Request("qfThreadInfo", &reply)) return false;
     306                 : 
     307               2 :   do {
     308                 :     // Check if we are done
     309               4 :     if (reply == "l") return true;
     310                 : 
     311               2 :     if (reply[0] != 'm') {
     312                 :       IPlatform::LogError("Expecting diffent thread format: %s\n",
     313               0 :                           reply.data());
     314               0 :       return false;
     315                 :     }
     316                 : 
     317               2 :     stringvec replys = StringSplit(&reply[1], ",");
     318               4 :     for (uint32_t loop = 0; loop < replys.size(); loop++) {
     319               2 :       ids->push_back(strtol(replys[loop].data(), NULL, 16));
     320               2 :     }
     321                 :   } while (Request("qsThreadInfo", &reply));
     322                 : 
     323               0 :   IPlatform::LogError("Failed request of qsThreadInfo.\n", reply.data());
     324               0 :   return false;
     325                 : }
     326                 : 
     327               1 : bool Host::HasProperty(const char *name) const {
     328               1 :   std::map<string, string>::const_iterator itr;
     329               1 :   itr = properties_.find(name);
     330                 : 
     331               1 :   return properties_.end() != itr;
     332                 : }
     333                 : 
     334               3 : bool Host::ReadProperty(const char *name, string* val) const {
     335               3 :   std::map<string, string>::const_iterator itr;
     336               3 :   itr = properties_.find(name);
     337                 : 
     338               3 :   if (properties_.end() == itr) return false;
     339                 : 
     340               3 :   *val = itr->second;
     341               3 :   return true;
     342                 : }
     343                 : 
     344                 : 
     345               1 : bool Host::ReadObject(const char *type, const char *name, string *reply) {
     346               1 :   uint32_t offset = 0;
     347               1 :   uint32_t maxTX = 1024;
     348               1 :   reply->clear();
     349                 : 
     350               1 :   if (ReadProperty("PacketSize", reply)) {
     351               1 :     maxTX = static_cast<uint32_t>(strtol(reply->data(), NULL, 16));
     352                 :   }
     353                 : 
     354               0 :   while (1) {
     355                 :     // We make this 64B to hold 2xlog16(2^64) + NUL + 14 characters although
     356                 :     // in practice these tend to be 16b values.
     357                 :     char tmp[64];
     358                 : 
     359               1 :     string replyPiece;
     360               1 :     string query = "qXfer:";
     361               1 :     query += type;
     362               1 :     query += ":read:";
     363               1 :     query += name;
     364               1 :     snprintf(tmp, sizeof(tmp), ":%x,%x", offset, maxTX);
     365               1 :     query += tmp;
     366                 : 
     367               1 :     if (!Request(query, &replyPiece)) return false;
     368                 : 
     369               1 :     if (replyPiece[0] == 'l') {
     370               1 :       *reply += &replyPiece[1];
     371               1 :       return true;
     372                 :     }
     373                 : 
     374               0 :     if ((replyPiece[0] == 'E') && (replyPiece.length() == 3)) {
     375               0 :       return false;
     376                 :     }
     377                 : 
     378               0 :     if (replyPiece[0] != 'm') {
     379                 :       IPlatform::LogError("Expecting more or end signal got:\n\t%s.",
     380               0 :                           replyPiece.data());
     381               0 :       return false;
     382                 :     }
     383                 : 
     384               0 :     *reply += replyPiece;
     385               0 :     offset += static_cast<uint32_t>(replyPiece.length());
     386                 :   }
     387                 : 
     388                 :   return true;
     389                 : }
     390                 : 
     391               0 : bool Host::Break() {
     392               0 :   char brk[2] = { 0x03, 0x00 };
     393                 : 
     394                 :   // We can only break if running
     395               0 :   if (HS_RUNNING != status_) return false;
     396                 : 
     397               0 :   status_ = HS_STOPPING;
     398               0 :   return RequestOnly(brk);
     399                 : }
     400                 : 
     401               0 : bool Host::Detach() {
     402                 :   // We can only detach if stopped
     403               0 :   if (HS_STOPPED != status_) return false;
     404                 : 
     405               0 :   return RequestOnly("d");
     406                 : }
     407                 : 
     408               2 : int32_t Host::GetSignal() {
     409                 :   // We always return the lasted cached value
     410               2 :   return lastSignal_;
     411                 : }
     412                 : 
     413               3 : Host::Status Host::GetStatus() {
     414               3 :   return status_;
     415                 : }
     416                 : 
     417               0 : bool Host::GetMemory(void *dst, uint64_t addr, uint32_t size) {
     418               0 :   char *ptr = reinterpret_cast<char *>(dst);
     419               0 :   uint32_t maxTX = 1024;
     420               0 :   string reply;
     421               0 :   Packet pktReq, pktReply;
     422                 : 
     423                 :   // We can only access memory if stopped
     424               0 :   if (HS_STOPPED != status_) return false;
     425                 : 
     426               0 :   if (ReadProperty("PacketSize", &reply)) {
     427               0 :     maxTX = strtoul(reply.data(), NULL, 16);
     428                 :   }
     429                 : 
     430                 :   // Reply is encoded as two nibbles plus a single char
     431                 :   // Mxxxxxxxx...
     432               0 :   maxTX = (maxTX - 1) / 2;
     433                 : 
     434               0 :   while (size) {
     435               0 :     uint32_t len = size;
     436               0 :     if (len > maxTX) len = maxTX;
     437                 : 
     438               0 :     pktReq.Clear();
     439               0 :     pktReq.AddRawChar('m');
     440               0 :     pktReq.AddNumberSep(addr, ',');
     441               0 :     pktReq.AddNumberSep(size, 0);
     442                 : 
     443               0 :     if (!Send(&pktReq, &pktReply)) return false;
     444                 : 
     445               0 :     if (!pktReply.GetBlock(ptr, len)) return false;
     446                 : 
     447               0 :     ptr += len;
     448               0 :     addr += len;
     449               0 :     size -= len;
     450                 :   }
     451                 : 
     452               0 :   return true;
     453                 : }
     454                 : 
     455               0 : bool Host::SetMemory(const void *src, uint64_t addr, uint32_t size) {
     456               0 :   const char *ptr = reinterpret_cast<const char *>(src);
     457               0 :   uint32_t maxTX = 1024;
     458               0 :   string reply;
     459               0 :   Packet pktReq, pktReply;
     460                 : 
     461                 :   // We can only access memory if stopped
     462               0 :   if (HS_STOPPED != status_) return false;
     463                 : 
     464               0 :   if (ReadProperty("PacketSize", &reply)) {
     465               0 :     maxTX = strtoul(reply.data(), NULL, 16);
     466                 :   }
     467                 : 
     468                 :   // Reply is encoded as two nibbles plus a single char(3), plus address (16)
     469                 :   // a and size (8) or Maaaaaaaaaaaaaaaa,ssssssss:(27)
     470               0 :   maxTX = (maxTX - 27) / 2;
     471                 : 
     472               0 :   while (size) {
     473               0 :     uint32_t len = size;
     474               0 :     if (len > maxTX) len = maxTX;
     475                 : 
     476               0 :     pktReq.Clear();
     477               0 :     pktReq.AddRawChar('M');
     478               0 :     pktReq.AddNumberSep(addr, ',');
     479               0 :     pktReq.AddNumberSep(len, ':');
     480               0 :     pktReq.AddBlock(src, len);
     481                 : 
     482               0 :     if (!Send(&pktReq, &pktReply)) return false;
     483                 : 
     484               0 :     ptr += len;
     485               0 :     addr += len;
     486               0 :     size -= len;
     487                 :   }
     488                 : 
     489               0 :   return true;
     490                 : }
     491                 : 
     492               0 : bool Host::RequestOnly(const string& req) {
     493               0 :   Packet pktReq;
     494                 : 
     495               0 :   pktReq.AddString(req.data());
     496               0 :   return SendOnly(&pktReq);
     497                 : }
     498                 : 
     499              10 : bool Host::Request(const string& req, string *resp) {
     500              10 :   Packet pktReq, pktResp;
     501                 : 
     502              10 :   pktReq.AddString(req.data());
     503              10 :   bool result = Send(&pktReq, &pktResp);
     504                 : 
     505              10 :   pktResp.GetString(resp);
     506                 : 
     507                 :   // Check for error code on return
     508              10 :   if ((resp->length() == 3) && (resp->data()[0] == 'E')) return false;
     509                 : 
     510              10 :   return result;
     511                 : }
     512                 : 
     513               1 : bool Host::SendOnly(Packet *tx) {
     514               1 :   return session_->SendPacketOnly(tx);
     515                 : }
     516                 : 
     517              12 : bool Host::Send(Packet *tx, Packet *rx) {
     518              12 :   if (!session_->SendPacket(tx)) return false;
     519              12 :   return session_->GetPacket(rx);
     520                 : }
     521                 : 
     522                 : }  // namespace gdb_rsp
     523                 : 
     524                 : 

Generated by: LCOV version 1.7