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 :
|