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 :
8 : #include <vector>
9 : #include <map>
10 :
11 : /*
12 : * NaCl Functions for intereacting with debuggers
13 : */
14 :
15 : #include "native_client/src/include/nacl_string.h"
16 : #include "native_client/src/shared/platform/nacl_check.h"
17 : #include "native_client/src/shared/platform/nacl_exit.h"
18 : #include "native_client/src/shared/platform/nacl_log.h"
19 : #include "native_client/src/shared/platform/nacl_threads.h"
20 : #include "native_client/src/trusted/debug_stub/debug_stub.h"
21 : #include "native_client/src/trusted/debug_stub/platform.h"
22 : #include "native_client/src/trusted/debug_stub/session.h"
23 : #include "native_client/src/trusted/debug_stub/target.h"
24 : #include "native_client/src/trusted/debug_stub/thread.h"
25 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
26 : #include "native_client/src/trusted/service_runtime/nacl_debug_init.h"
27 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
28 : #include "native_client/src/trusted/service_runtime/thread_suspension.h"
29 :
30 : using port::IPlatform;
31 : using port::IThread;
32 : using port::ITransport;
33 : using port::SocketBinding;
34 :
35 : using gdb_rsp::Session;
36 : using gdb_rsp::Target;
37 :
38 : #if NACL_WINDOWS
39 : /* Disable warning for unwind disabled when exceptions used */
40 : #pragma warning(disable:4530)
41 : #endif
42 :
43 :
44 : static Target *g_target = NULL;
45 : static SocketBinding *g_socket_binding = NULL;
46 :
47 : int NaClDebugBindSocket() {
48 34 : if (g_socket_binding == NULL) {
49 17 : NaClDebugStubInit();
50 : // Try port 4014 first for compatibility.
51 17 : g_socket_binding = SocketBinding::Bind("127.0.0.1:4014");
52 : // If port 4014 is not available, try any port.
53 17 : if (g_socket_binding == NULL) {
54 0 : g_socket_binding = SocketBinding::Bind("127.0.0.1:0");
55 0 : }
56 17 : if (g_socket_binding == NULL) {
57 0 : NaClLog(LOG_ERROR,
58 : "NaClDebugStubBindSocket: Failed to bind any TCP port\n");
59 0 : return 0;
60 : }
61 17 : NaClLog(LOG_WARNING,
62 : "nacl_debug(%d) : Connect GDB with 'target remote :%d\n",
63 17 : __LINE__, g_socket_binding->GetBoundPort());
64 17 : }
65 34 : return 1;
66 34 : }
67 :
68 0 : void NaClDebugSetBoundSocket(NaClSocketHandle bound_socket) {
69 0 : CHECK(g_socket_binding == NULL);
70 0 : g_socket_binding = new SocketBinding(bound_socket);
71 0 : }
72 :
73 17 : void WINAPI NaClStubThread(void *thread_arg) {
74 34 : UNREFERENCED_PARAMETER(thread_arg);
75 :
76 17 : while (1) {
77 : // Wait for a connection.
78 29 : nacl::scoped_ptr<ITransport> trans(g_socket_binding->AcceptConnection());
79 58 : if (NULL == trans.get()) continue;
80 :
81 : // Create a new session for this connection
82 58 : Session ses(trans.get());
83 29 : ses.SetFlags(Session::DEBUG_MASK);
84 :
85 29 : NaClLog(LOG_WARNING, "nacl_debug(%d) : Connected, happy debugging!\n",
86 : __LINE__);
87 :
88 : // Run this session for as long as it lasts
89 14 : g_target->Run(&ses);
90 70 : }
91 0 : }
92 :
93 20 : static void ThreadCreateHook(struct NaClAppThread *natp) throw() {
94 20 : g_target->TrackThread(natp);
95 20 : }
96 :
97 3 : static void ThreadExitHook(struct NaClAppThread *natp) throw() {
98 3 : g_target->IgnoreThread(natp);
99 3 : }
100 :
101 : static void ProcessExitHook() throw() {
102 2 : g_target->Exit();
103 2 : NaClDebugStubFini();
104 2 : }
105 :
106 : static const struct NaClDebugCallbacks debug_callbacks = {
107 : ThreadCreateHook,
108 : ThreadExitHook,
109 : ProcessExitHook,
110 : };
111 :
112 : /*
113 : * This function is implemented for the service runtime. The service runtime
114 : * declares the function so it does not need to be declared in our header.
115 : */
116 17 : int NaClDebugInit(struct NaClApp *nap) {
117 17 : if (!NaClFaultedThreadQueueEnable(nap)) {
118 0 : NaClLog(LOG_ERROR, "NaClDebugInit: Failed to initialize fault handling\n");
119 0 : return 0;
120 : }
121 17 : nap->debug_stub_callbacks = &debug_callbacks;
122 :
123 51 : CHECK(g_target == NULL);
124 34 : g_target = new Target(nap);
125 51 : CHECK(g_target != NULL);
126 17 : g_target->Init();
127 :
128 17 : if (!NaClDebugBindSocket()) {
129 0 : return 0;
130 : }
131 : #if NACL_WINDOWS
132 : nap->debug_stub_port = g_socket_binding->GetBoundPort();
133 : #endif
134 :
135 17 : NaClThread *thread = new NaClThread;
136 51 : CHECK(thread != NULL);
137 :
138 17 : NaClLog(LOG_WARNING, "nacl_debug(%d) : Debugging started.\n", __LINE__);
139 51 : CHECK(NaClThreadCtor(thread, NaClStubThread, NULL, NACL_KERN_STACK_SIZE));
140 :
141 17 : return 1;
142 17 : }
|