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 34 : 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 68 : should_exit_(false) {
73 51 : if (NULL == abi_) abi_ = Abi::Get();
74 34 : }
75 :
76 0 : Target::~Target() {
77 0 : Destroy();
78 0 : }
79 :
80 : bool Target::Init() {
81 34 : string targ_xml = "l<target><architecture>";
82 :
83 34 : targ_xml += abi_->GetName();
84 17 : targ_xml += "</architecture><osabi>NaCl</osabi>";
85 34 : targ_xml += abi_->GetTargetXml();
86 17 : targ_xml += "</target>";
87 :
88 : // Set a more specific result which won't change.
89 85 : properties_["target.xml"] = targ_xml;
90 85 : properties_["Supported"] =
91 : "PacketSize=1000;qXfer:features:read+";
92 :
93 17 : NaClXMutexCtor(&mutex_);
94 51 : ctx_ = new uint8_t[abi_->GetContextSize()];
95 :
96 17 : initial_breakpoint_addr_ = (uint32_t) nap_->initial_entry_pt;
97 34 : if (!AddBreakpoint(initial_breakpoint_addr_))
98 0 : return false;
99 34 : return true;
100 17 : }
101 :
102 : void Target::Destroy() {
103 0 : NaClMutexDtor(&mutex_);
104 :
105 0 : delete[] ctx_;
106 0 : }
107 :
108 69 : bool Target::AddBreakpoint(uint32_t user_address) {
109 69 : const Abi::BPDef *bp = abi_->GetBreakpointDef();
110 :
111 : // If we already have a breakpoint here then don't add it
112 69 : if (breakpoint_map_.find(user_address) != breakpoint_map_.end())
113 0 : return false;
114 :
115 69 : uintptr_t sysaddr = NaClUserToSysAddrRange(nap_, user_address, bp->size_);
116 69 : if (sysaddr == kNaClBadAddress)
117 0 : return false;
118 : // We allow setting breakpoints in the code area but not the data area.
119 69 : 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 69 : uint8_t *data = new uint8_t[bp->size_];
128 :
129 : // Copy the old code from here
130 69 : if (!IPlatform::GetMemory(sysaddr, bp->size_, data)) {
131 2 : delete[] data;
132 1 : return false;
133 : }
134 68 : if (!IPlatform::SetMemory(nap_, sysaddr, bp->size_, bp->code_)) {
135 0 : delete[] data;
136 0 : return false;
137 : }
138 :
139 68 : breakpoint_map_[user_address] = data;
140 68 : return true;
141 69 : }
142 :
143 68 : bool Target::RemoveBreakpoint(uint32_t user_address) {
144 68 : const Abi::BPDef *bp_def = abi_->GetBreakpointDef();
145 :
146 68 : BreakpointMap_t::iterator iter = breakpoint_map_.find(user_address);
147 68 : if (iter == breakpoint_map_.end())
148 0 : return false;
149 :
150 68 : uintptr_t sysaddr = NaClUserToSys(nap_, user_address);
151 68 : uint8_t *data = iter->second;
152 : // Copy back the old code, and free the data
153 68 : 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 136 : delete[] data;
158 68 : breakpoint_map_.erase(iter);
159 68 : return true;
160 68 : }
161 :
162 92 : void Target::CopyFaultSignalFromAppThread(IThread *thread) {
163 182 : if (thread->GetFaultSignal() == 0 && thread->HasThreadFaulted()) {
164 84 : 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 48 : uint32_t prog_ctr = (uint32_t) thread->GetContext()->prog_ctr;
189 48 : if (breakpoint_map_.find(prog_ctr) != breakpoint_map_.end()) {
190 48 : signal = NACL_ABI_SIGTRAP;
191 48 : }
192 48 : }
193 84 : thread->SetFaultSignal(signal);
194 84 : }
195 92 : }
196 :
197 : void Target::RemoveInitialBreakpoint() {
198 84 : if (initial_breakpoint_addr_ != 0) {
199 17 : if (!RemoveBreakpoint(initial_breakpoint_addr_)) {
200 0 : NaClLog(LOG_FATAL,
201 : "RemoveInitialBreakpoint: Failed to remove breakpoint\n");
202 0 : }
203 17 : initial_breakpoint_addr_ = 0;
204 17 : }
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 462 : void Target::EraseBreakpointsFromCopyOfMemory(uint32_t user_address,
212 462 : uint8_t *data, uint32_t size) {
213 462 : uint32_t user_end = user_address + size;
214 462 : const Abi::BPDef *bp = abi_->GetBreakpointDef();
215 462 : for (BreakpointMap_t::iterator iter = breakpoint_map_.begin();
216 654 : iter != breakpoint_map_.end();
217 192 : ++iter) {
218 192 : uint32_t breakpoint_address = iter->first;
219 192 : uint32_t breakpoint_end = breakpoint_address + bp->size_;
220 192 : uint8_t *original_data = iter->second;
221 :
222 192 : uint32_t overlap_start = std::max(user_address, breakpoint_address);
223 192 : uint32_t overlap_end = std::min(user_end, breakpoint_end);
224 192 : if (overlap_start < overlap_end) {
225 82 : uint8_t *dest = data + (overlap_start - user_address);
226 82 : uint8_t *src = original_data + (overlap_start - breakpoint_address);
227 82 : size_t copy_size = overlap_end - overlap_start;
228 : // Sanity check: do some bounds checks.
229 328 : CHECK(data <= dest && dest + copy_size <= data + size);
230 328 : CHECK(original_data <= src
231 : && src + copy_size <= original_data + bp->size_);
232 82 : memcpy(dest, src, copy_size);
233 82 : }
234 192 : }
235 462 : }
236 :
237 29 : void Target::Run(Session *ses) {
238 29 : NaClXMutexLock(&mutex_);
239 29 : session_ = ses;
240 29 : NaClXMutexUnlock(&mutex_);
241 :
242 29 : do {
243 160 : WaitForDebugEvent();
244 :
245 : // Lock to prevent anyone else from modifying threads
246 : // or updating the signal information.
247 160 : MutexLock lock(&mutex_);
248 :
249 160 : ProcessDebugEvent();
250 145 : ProcessCommands();
251 290 : } while (session_->Connected());
252 :
253 14 : NaClXMutexLock(&mutex_);
254 14 : session_ = NULL;
255 14 : NaClXMutexUnlock(&mutex_);
256 14 : }
257 :
258 : bool Target::IsInitialBreakpointActive() {
259 160 : return initial_breakpoint_addr_ != 0;
260 : }
261 :
262 : void Target::WaitForDebugEvent() {
263 160 : 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 12 : return;
267 : }
268 : // Wait for either:
269 : // * an untrusted thread to fault (or single-step)
270 : // * an interrupt from GDB
271 148 : bool ignore_input_from_gdb = step_over_breakpoint_thread_ != 0 ||
272 222 : IsInitialBreakpointActive();
273 148 : session_->WaitForDebugStubEvent(nap_, ignore_input_from_gdb);
274 308 : }
275 :
276 : void Target::ProcessDebugEvent() {
277 160 : if (all_threads_suspended_) {
278 : // We are already in a suspended state.
279 12 : return;
280 148 : } 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 74 : IThread *thread = threads_[step_over_breakpoint_thread_];
289 74 : 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 63 : 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 85 : } 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 73 : } 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 2 : 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 84 : }
342 :
343 : // Next update the current thread info
344 85 : char tmp[16];
345 85 : snprintf(tmp, sizeof(tmp), "QC%x", sig_thread_);
346 425 : 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 68 : Packet pktOut;
352 68 : SetStopReply(&pktOut);
353 68 : session_->SendPacketOnly(&pktOut);
354 68 : }
355 :
356 85 : all_threads_suspended_ = true;
357 245 : }
358 :
359 : void Target::ProcessCommands() {
360 160 : if (!all_threads_suspended_) {
361 : // Don't process commands if we haven't stopped all threads.
362 63 : 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 97 : do {
369 2374 : if (!session_->GetPacket(&recv))
370 13 : continue;
371 1174 : reply.Clear();
372 2348 : if (ProcessPacket(&recv, &reply)) {
373 : // If this is a continue type command, break out of this loop.
374 68 : break;
375 : }
376 : // Otherwise send the response.
377 1106 : session_->SendPacket(&reply);
378 :
379 1106 : if (detaching_) {
380 1 : detaching_ = false;
381 1 : session_->Disconnect();
382 1 : Resume();
383 1 : return;
384 : }
385 :
386 1105 : if (should_exit_) {
387 0 : NaClExit(-9);
388 0 : }
389 3296 : } while (session_->Connected());
390 :
391 162 : if (session_->Connected()) {
392 : // Continue if we're still connected.
393 68 : Resume();
394 68 : }
395 453 : }
396 :
397 : void Target::Resume() {
398 : // Reset the signal value
399 69 : 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 69 : if (step_over_breakpoint_thread_ == 0) {
404 58 : ResumeAllThreads();
405 58 : } else {
406 : // Resume one thread while leaving all others suspended.
407 11 : threads_[step_over_breakpoint_thread_]->ResumeThread();
408 : }
409 :
410 69 : all_threads_suspended_ = false;
411 69 : }
412 :
413 97 : void Target::SetStopReply(Packet *pktOut) const {
414 97 : pktOut->AddRawChar('T');
415 97 : 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 97 : if (sig_thread_ != 0) {
424 : // Add 'thread:<tid>;' pair. Note terminating ';' is required.
425 96 : pktOut->AddString("thread:");
426 96 : pktOut->AddNumberSep(sig_thread_, ';');
427 96 : }
428 97 : }
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 4 : if (threadItr_ == threads_.end()) return false;
438 :
439 2 : *id = (*threadItr_).first;
440 2 : threadItr_++;
441 :
442 2 : return true;
443 3 : }
444 :
445 :
446 469 : 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 469 : NaClIsUserAddr(nap_, (uintptr_t) addr)) {
452 17 : return NaClSysToUser(nap_, (uintptr_t) addr);
453 : }
454 : // Otherwise, we expect an untrusted address.
455 452 : return addr;
456 469 : }
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 101 : void Target::ProcessFilePacket(Packet *pktIn, Packet *pktOut, ErrDef *err) {
465 101 : std::string cmd;
466 202 : if (!pktIn->GetStringSep(&cmd, ':')) {
467 0 : *err = BAD_FORMAT;
468 0 : return;
469 : }
470 505 : CHECK(cmd == "File");
471 101 : std::string subcmd;
472 202 : if (!pktIn->GetStringSep(&subcmd, ':')) {
473 0 : *err = BAD_FORMAT;
474 0 : return;
475 : }
476 202 : if (subcmd == "open") {
477 1 : std::string filename;
478 1 : char sep;
479 1 : uint64_t flags;
480 1 : uint64_t mode;
481 2 : if (!pktIn->GetHexString(&filename) ||
482 3 : !pktIn->GetRawChar(&sep) ||
483 : sep != ',' ||
484 2 : !pktIn->GetNumberSep(&flags, NULL) ||
485 2 : !pktIn->GetNumberSep(&mode, NULL)) {
486 0 : *err = BAD_ARGS;
487 0 : return;
488 : }
489 2 : if (filename == kMainNexeFilename) {
490 1 : if (flags == kGdbO_RDONLY) {
491 1 : pktOut->AddString("F");
492 1 : pktOut->AddNumberSep(kMainNexeFd, 0);
493 1 : } else {
494 0 : EmitFileError(pktOut, kGdbEPERM);
495 : }
496 1 : } else if (filename == kIrtNexeFilename) {
497 0 : if (flags == kGdbO_RDONLY) {
498 0 : pktOut->AddString("F");
499 0 : pktOut->AddNumberSep(kIrtNexeFd, 0);
500 0 : } else {
501 0 : EmitFileError(pktOut, kGdbEPERM);
502 : }
503 0 : } else {
504 0 : EmitFileError(pktOut, kGdbENOENT);
505 : }
506 1 : return;
507 201 : } else if (subcmd == "close") {
508 1 : uint64_t fd;
509 2 : if (!pktIn->GetNumberSep(&fd, NULL)) {
510 0 : *err = BAD_ARGS;
511 0 : return;
512 : }
513 1 : if (fd == kMainNexeFd) {
514 1 : pktOut->AddString("F");
515 1 : pktOut->AddNumberSep(0, 0);
516 1 : } else if (fd == kIrtNexeFd) {
517 0 : pktOut->AddString("F");
518 0 : pktOut->AddNumberSep(0, 0);
519 0 : } else {
520 0 : EmitFileError(pktOut, kGdbEBADF);
521 : }
522 1 : return;
523 198 : } else if (subcmd == "pread") {
524 99 : uint64_t fd;
525 99 : uint64_t count;
526 99 : uint64_t offset;
527 99 : std::string data;
528 198 : if (!pktIn->GetNumberSep(&fd, NULL) ||
529 198 : !pktIn->GetNumberSep(&count, NULL) ||
530 198 : !pktIn->GetNumberSep(&offset, NULL)) {
531 0 : *err = BAD_ARGS;
532 0 : return;
533 : }
534 99 : NaClDesc *desc;
535 99 : if (fd == kMainNexeFd) {
536 99 : desc = nap_->main_nexe_desc;
537 99 : } else if (fd == kIrtNexeFd) {
538 0 : desc = nap_->irt_nexe_desc;
539 0 : } else {
540 0 : EmitFileError(pktOut, kGdbEBADF);
541 0 : return;
542 : }
543 396 : CHECK(NULL != desc);
544 99 : if (count > kGdbPreadChunkSize) {
545 0 : count = kGdbPreadChunkSize;
546 0 : }
547 198 : nacl::scoped_array<char> buffer(new char[kGdbPreadChunkSize]);
548 297 : ssize_t result = (*NACL_VTBL(NaClDesc, desc)->PRead)(
549 99 : desc, buffer.get(),
550 : static_cast<size_t>(count),
551 : static_cast<nacl_off64_t>(offset));
552 99 : pktOut->AddString("F");
553 99 : if (result < 0) {
554 0 : pktOut->AddNumberSep(kGdbErrorResult, ',');
555 0 : pktOut->AddNumberSep(static_cast<uint64_t>(-result), 0);
556 0 : } else {
557 99 : pktOut->AddNumberSep(static_cast<uint64_t>(result), ';');
558 198 : pktOut->AddEscapedData(buffer.get(), static_cast<size_t>(result));
559 : }
560 : return;
561 198 : }
562 0 : NaClLog(LOG_ERROR, "Unknown vFile command: %s\n", pktIn->GetPayload());
563 0 : *err = BAD_FORMAT;
564 303 : }
565 :
566 1174 : bool Target::ProcessPacket(Packet* pktIn, Packet* pktOut) {
567 1174 : char cmd;
568 1174 : int32_t seq = -1;
569 1174 : ErrDef err = NONE;
570 :
571 : // Clear the outbound message
572 1174 : pktOut->Clear();
573 :
574 : // Pull out the sequence.
575 1174 : pktIn->GetSequence(&seq);
576 1174 : if (seq != -1) pktOut->SetSequence(seq);
577 :
578 : // Find the command
579 1174 : pktIn->GetRawChar(&cmd);
580 :
581 1174 : 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 1 : Detach();
595 1 : pktOut->AddString("OK");
596 1 : return false;
597 :
598 : // IN : $k
599 : // OUT: $OK
600 : case 'k':
601 15 : Kill();
602 15 : pktOut->AddString("OK");
603 15 : return false;
604 :
605 : // IN : $g
606 : // OUT: $xx...xx
607 : case 'g': {
608 100 : IThread *thread = GetRegThread();
609 100 : if (NULL == thread) {
610 0 : err = BAD_ARGS;
611 0 : break;
612 : }
613 :
614 : // Copy OS preserved registers to GDB payload
615 5000 : for (uint32_t a = 0; a < abi_->GetRegisterCount(); a++) {
616 2400 : const Abi::RegDef *def = abi_->GetRegisterDef(a);
617 2400 : thread->GetRegister(a, &ctx_[def->offset_], def->bytes_);
618 2400 : }
619 :
620 100 : pktOut->AddBlock(ctx_, abi_->GetContextSize());
621 100 : break;
622 : }
623 :
624 : // IN : $Gxx..xx
625 : // OUT: $OK
626 : case 'G': {
627 16 : IThread *thread = GetRegThread();
628 16 : if (NULL == thread) {
629 0 : err = BAD_ARGS;
630 0 : break;
631 : }
632 :
633 16 : pktIn->GetBlock(ctx_, abi_->GetContextSize());
634 :
635 : // GDB payload to OS registers
636 800 : for (uint32_t a = 0; a < abi_->GetRegisterCount(); a++) {
637 384 : const Abi::RegDef *def = abi_->GetRegisterDef(a);
638 384 : thread->SetRegister(a, &ctx_[def->offset_], def->bytes_);
639 384 : }
640 :
641 16 : pktOut->AddString("OK");
642 16 : break;
643 : }
644 :
645 : // IN : $H(c/g)(-1,0,xxxx)
646 : // OUT: $OK
647 : case 'H': {
648 61 : char type;
649 61 : uint64_t id;
650 :
651 61 : if (!pktIn->GetRawChar(&type)) {
652 0 : err = BAD_FORMAT;
653 0 : break;
654 : }
655 61 : if (!pktIn->GetNumberSep(&id, 0)) {
656 0 : err = BAD_FORMAT;
657 0 : break;
658 : }
659 :
660 61 : 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 90 : if (id == static_cast<uint64_t>(-1)) id = threads_.begin()->first;
667 :
668 : // Verify that we have the thread
669 61 : if (threads_.find(static_cast<uint32_t>(id)) == threads_.end()) {
670 29 : err = BAD_ARGS;
671 29 : break;
672 : }
673 :
674 61 : pktOut->AddString("OK");
675 61 : switch (type) {
676 : case 'g':
677 3 : reg_thread_ = static_cast<uint32_t>(id);
678 32 : 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 32 : break;
687 : }
688 :
689 : // IN : $maaaa,llll
690 : // OUT: $xx..xx
691 : case 'm': {
692 465 : uint64_t user_addr;
693 465 : uint64_t wlen;
694 465 : uint32_t len;
695 465 : if (!pktIn->GetNumberSep(&user_addr, 0)) {
696 0 : err = BAD_FORMAT;
697 0 : break;
698 : }
699 465 : if (!pktIn->GetNumberSep(&wlen, 0)) {
700 0 : err = BAD_FORMAT;
701 0 : break;
702 : }
703 465 : user_addr = AdjustUserAddr(user_addr);
704 465 : uint64_t sys_addr = NaClUserToSysAddrRange(nap_, (uintptr_t) user_addr,
705 : (size_t) wlen);
706 465 : if (sys_addr == kNaClBadAddress) {
707 0 : err = FAILED;
708 0 : break;
709 : }
710 :
711 465 : len = static_cast<uint32_t>(wlen);
712 465 : nacl::scoped_array<uint8_t> block(new uint8_t[len]);
713 1395 : if (!port::IPlatform::GetMemory(sys_addr, len, block.get())) {
714 3 : err = FAILED;
715 3 : break;
716 : }
717 924 : EraseBreakpointsFromCopyOfMemory((uint32_t) user_addr,
718 462 : block.get(), len);
719 :
720 924 : pktOut->AddBlock(block.get(), len);
721 462 : break;
722 465 : }
723 :
724 : // IN : $Maaaa,llll:xx..xx
725 : // OUT: $OK
726 : case 'M': {
727 4 : uint64_t user_addr;
728 4 : uint64_t wlen;
729 4 : uint32_t len;
730 :
731 4 : if (!pktIn->GetNumberSep(&user_addr, 0)) {
732 0 : err = BAD_FORMAT;
733 0 : break;
734 : }
735 4 : if (!pktIn->GetNumberSep(&wlen, 0)) {
736 0 : err = BAD_FORMAT;
737 0 : break;
738 : }
739 4 : user_addr = AdjustUserAddr(user_addr);
740 4 : uint64_t sys_addr = NaClUserToSysAddrRange(nap_, (uintptr_t) user_addr,
741 : (size_t) wlen);
742 4 : if (sys_addr == kNaClBadAddress) {
743 0 : err = FAILED;
744 0 : break;
745 : }
746 4 : len = static_cast<uint32_t>(wlen);
747 : // We disallow the debugger from modifying code.
748 4 : if (user_addr < nap_->dynamic_text_end) {
749 0 : err = FAILED;
750 0 : break;
751 : }
752 :
753 4 : nacl::scoped_array<uint8_t> block(new uint8_t[len]);
754 8 : pktIn->GetBlock(block.get(), len);
755 :
756 12 : if (!port::IPlatform::SetMemory(nap_, sys_addr, len, block.get())) {
757 0 : err = FAILED;
758 0 : break;
759 : }
760 :
761 4 : pktOut->AddString("OK");
762 4 : break;
763 4 : }
764 :
765 : case 'q': {
766 180 : string tmp;
767 360 : const char *str = &pktIn->GetPayload()[1];
768 720 : stringvec toks = StringSplit(str, ":;");
769 540 : PropertyMap_t::const_iterator itr = properties_.find(toks[0]);
770 :
771 : // If this is a thread query
772 718 : if (!strcmp(str, "fThreadInfo") || !strcmp(str, "sThreadInfo")) {
773 3 : uint32_t curr;
774 3 : bool more = false;
775 3 : if (str[0] == 'f') {
776 2 : more = GetFirstThreadId(&curr);
777 1 : } else {
778 4 : more = GetNextThreadId(&curr);
779 : }
780 :
781 3 : if (!more) {
782 1 : pktOut->AddString("l");
783 1 : } else {
784 2 : pktOut->AddString("m");
785 2 : pktOut->AddNumberSep(curr, 0);
786 : }
787 3 : break;
788 : }
789 :
790 : // Check for architecture query
791 177 : tmp = "Xfer:features:read:target.xml";
792 708 : if (!strncmp(str, tmp.data(), tmp.length())) {
793 145 : stringvec args = StringSplit(&str[tmp.length()+1], ",");
794 58 : if (args.size() != 2) break;
795 :
796 145 : const char *out = properties_["target.xml"].data();
797 116 : int offs = strtol(args[0].data(), NULL, 16);
798 116 : int max = strtol(args[1].data(), NULL, 16) + offs;
799 58 : int len = static_cast<int>(strlen(out));
800 :
801 58 : if (max >= len) max = len;
802 :
803 2291 : while (offs < max) {
804 2233 : pktOut->AddRawChar(out[offs]);
805 2233 : offs++;
806 2233 : }
807 29 : break;
808 29 : }
809 :
810 : // Check the property cache
811 592 : if (itr != properties_.end()) {
812 87 : pktOut->AddString(itr->second.data());
813 29 : }
814 148 : break;
815 360 : }
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 5 : 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 187 : const char *str = pktIn->GetPayload() + 1;
841 :
842 187 : if (strncmp(str, "Cont", 4) == 0) {
843 : // vCont
844 86 : const char *subcommand = str + 4;
845 :
846 86 : 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 68 : if (strcmp(subcommand, ";c") == 0) {
853 : // Continue all threads.
854 32 : return true;
855 : }
856 :
857 36 : if (strncmp(subcommand, ";s:", 3) == 0) {
858 : // Single step one thread and optionally continue all other threads.
859 36 : char *end;
860 36 : uint32_t thread_id = static_cast<uint32_t>(
861 36 : strtol(subcommand + 3, &end, 16));
862 36 : if (end == subcommand + 3) {
863 0 : err = BAD_ARGS;
864 0 : break;
865 : }
866 :
867 36 : ThreadMap_t::iterator it = threads_.find(thread_id);
868 36 : if (it == threads_.end()) {
869 0 : err = BAD_ARGS;
870 0 : break;
871 : }
872 :
873 36 : 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 36 : } else if (strcmp(end, ";c") == 0) {
888 : // Single step one thread and continue all other threads.
889 25 : } else {
890 : // Unsupported combination of single step and other args.
891 0 : err = BAD_ARGS;
892 0 : break;
893 : }
894 :
895 36 : it->second->SetStep(true);
896 36 : 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 0 : char *end;
915 0 : 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 0 : }
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 101 : } else if (strncmp(str, "File:", 5) == 0) {
932 101 : ProcessFilePacket(pktIn, pktOut, &err);
933 101 : break;
934 : }
935 :
936 0 : NaClLog(LOG_ERROR, "Unknown command: %s\n", pktIn->GetPayload());
937 0 : return false;
938 : }
939 :
940 : case 'Z': {
941 52 : uint64_t breakpoint_type;
942 52 : uint64_t breakpoint_address;
943 52 : uint64_t breakpoint_kind;
944 104 : if (!pktIn->GetNumberSep(&breakpoint_type, 0) ||
945 : breakpoint_type != 0 ||
946 52 : !pktIn->GetNumberSep(&breakpoint_address, 0) ||
947 52 : !pktIn->GetNumberSep(&breakpoint_kind, 0)) {
948 0 : err = BAD_FORMAT;
949 0 : break;
950 : }
951 52 : if (breakpoint_address != (uint32_t) breakpoint_address ||
952 52 : !AddBreakpoint((uint32_t) breakpoint_address)) {
953 1 : err = FAILED;
954 1 : break;
955 : }
956 51 : pktOut->AddString("OK");
957 51 : break;
958 : }
959 :
960 : case 'z': {
961 51 : uint64_t breakpoint_type;
962 51 : uint64_t breakpoint_address;
963 51 : uint64_t breakpoint_kind;
964 102 : if (!pktIn->GetNumberSep(&breakpoint_type, 0) ||
965 : breakpoint_type != 0 ||
966 51 : !pktIn->GetNumberSep(&breakpoint_address, 0) ||
967 51 : !pktIn->GetNumberSep(&breakpoint_kind, 0)) {
968 0 : err = BAD_FORMAT;
969 0 : break;
970 : }
971 51 : if (breakpoint_address != (uint32_t) breakpoint_address ||
972 51 : !RemoveBreakpoint((uint32_t) breakpoint_address)) {
973 0 : err = FAILED;
974 0 : break;
975 : }
976 51 : pktOut->AddString("OK");
977 51 : 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 16 : NaClLog(LOG_ERROR, "Unknown command: %s\n", pktIn->GetPayload());
986 8 : return false;
987 8 : }
988 : }
989 :
990 : // If there is an error, return the error code instead of a payload
991 1082 : if (err) {
992 62 : pktOut->Clear();
993 62 : pktOut->AddRawChar('E');
994 62 : pktOut->AddWord8(err);
995 62 : }
996 1082 : return false;
997 1174 : }
998 :
999 :
1000 20 : 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 20 : uint32_t id = natp->thread_num + 1;
1004 20 : MutexLock lock(&mutex_);
1005 100 : CHECK(threads_[id] == 0);
1006 60 : threads_[id] = IThread::Create(id, natp);
1007 20 : }
1008 :
1009 3 : void Target::IgnoreThread(struct NaClAppThread *natp) {
1010 3 : uint32_t id = natp->thread_num + 1;
1011 3 : MutexLock lock(&mutex_);
1012 6 : ThreadMap_t::iterator iter = threads_.find(id);
1013 18 : CHECK(iter != threads_.end());
1014 12 : delete iter->second;
1015 3 : threads_.erase(iter);
1016 3 : }
1017 :
1018 : void Target::Exit() {
1019 2 : MutexLock lock(&mutex_);
1020 2 : 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 0 : } 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 2 : }
1031 2 : }
1032 :
1033 : void Target::Detach() {
1034 1 : NaClLog(LOG_INFO, "Requested Detach.\n");
1035 1 : detaching_ = true;
1036 1 : }
1037 :
1038 : void Target::Kill() {
1039 15 : NaClLog(LOG_INFO, "Requested Kill.\n");
1040 15 : should_exit_ = true;
1041 15 : }
1042 :
1043 : IThread* Target::GetRegThread() {
1044 116 : ThreadMap_t::const_iterator itr;
1045 :
1046 116 : 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 116 : itr = threads_.find(reg_thread_);
1055 116 : break;
1056 : }
1057 :
1058 116 : if (itr == threads_.end()) return 0;
1059 :
1060 116 : return itr->second;
1061 116 : }
1062 :
1063 : 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 0 : }
1074 :
1075 5 : IThread* Target::GetThread(uint32_t id) {
1076 5 : ThreadMap_t::const_iterator itr;
1077 5 : itr = threads_.find(id);
1078 10 : if (itr != threads_.end()) return itr->second;
1079 :
1080 0 : return NULL;
1081 5 : }
1082 :
1083 : void Target::SuspendAllThreads() {
1084 74 : NaClUntrustedThreadsSuspendAll(nap_, /* save_registers= */ 1);
1085 74 : for (ThreadMap_t::const_iterator iter = threads_.begin();
1086 155 : iter != threads_.end();
1087 81 : ++iter) {
1088 81 : IThread *thread = iter->second;
1089 81 : thread->CopyRegistersFromAppThread();
1090 81 : CopyFaultSignalFromAppThread(thread);
1091 81 : }
1092 74 : }
1093 :
1094 : void Target::ResumeAllThreads() {
1095 58 : for (ThreadMap_t::const_iterator iter = threads_.begin();
1096 122 : iter != threads_.end();
1097 64 : ++iter) {
1098 64 : iter->second->CopyRegistersToAppThread();
1099 64 : }
1100 58 : NaClUntrustedThreadsResumeAll(nap_);
1101 58 : }
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 73 : for (ThreadMap_t::const_iterator iter = threads_.begin();
1109 79 : iter != threads_.end();
1110 6 : ++iter) {
1111 79 : IThread *thread = iter->second;
1112 79 : if (thread->GetFaultSignal() != 0) {
1113 73 : *signal = thread->GetFaultSignal();
1114 73 : *thread_id = thread->GetId();
1115 73 : thread->UnqueueFaultedThread();
1116 73 : return;
1117 : }
1118 6 : }
1119 0 : NaClLog(LOG_FATAL, "UnqueueAnyFaultedThread: No threads queued\n");
1120 73 : }
1121 :
1122 : } // namespace gdb_rsp
|