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