OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 #include "debugger/core/debug_api.h" | |
5 #include <signal.h> | |
6 #include <stdio.h> | |
7 #include <algorithm> | |
8 #include "debugger/base/debug_command_line.h" | |
9 #include "debugger/core/debuggee_process.h" | |
10 #include "debugger/core/debuggee_thread.h" | |
11 | |
12 namespace { | |
13 const int kWatForAllThreadsToStopSecs = 3; | |
14 void delete_obj(debug::DebuggeeThread* obj) { delete obj; } | |
15 } // namespace | |
16 | |
17 namespace debug { | |
18 | |
19 DebuggeeProcess::DebuggeeProcess (DebugAPI* debug_api) | |
20 : debug_api_(*debug_api), | |
21 nexe_mem_base_(0), | |
22 stopping_treads_(false), | |
23 is_first_event_(true) { | |
24 } | |
25 | |
26 DebuggeeProcess::~DebuggeeProcess() { | |
27 std::for_each(threads_.begin(), threads_.end(), delete_obj); | |
28 threads_.clear(); | |
29 } | |
30 | |
31 DebuggeeThread* DebuggeeProcess::GetThread(int tid) { | |
32 ThreadConstIter it = threads_.begin(); | |
33 while (it != threads_.end()) { | |
34 DebuggeeThread* thread = *it; | |
35 if (tid == thread->id()) | |
36 return thread; | |
37 ++it; | |
38 } | |
39 return NULL; | |
40 } | |
41 | |
42 void DebuggeeProcess::GetThreadsIds(std::deque<int>* threads) const { | |
43 threads->clear(); | |
44 ThreadConstIter it = threads_.begin(); | |
45 while (it != threads_.end()) { | |
46 threads->push_back((*it)->id()); | |
47 ++it; | |
48 } | |
49 } | |
50 | |
51 bool DebuggeeProcess::WaitForDebugEventAndDispatchIt(DebugEvent* debug_event) { | |
52 while (debug_api_.WaitForDebugEvent(debug_event)) { | |
53 if (is_first_event_) { | |
54 is_first_event_ = false; | |
55 debug_api_.SetupProc(debug_event->pid_); // Make it trace all children. | |
56 } | |
57 if (OnDebugEvent(*debug_event)) | |
58 return true; | |
59 } | |
60 return false; | |
61 } | |
62 | |
63 | |
64 bool DebuggeeProcess::OnDebugEvent(const DebugEvent& debug_event) { | |
65 DebuggeeThread* thread = GetThread(debug_event.pid_); | |
66 if (NULL == thread) { | |
67 // Check if it's 'OUTPUT_DEBUG_STRING' event | |
68 std::string str; | |
69 if (debug_api_.ReadDebugString(debug_event, &str)) { | |
70 // parse it | |
71 CommandLine debug_info(str); | |
72 std::string event = debug_info.GetStringSwitch("-event", ""); | |
73 if ("AppCreate" == event) { | |
74 void* mem_base = debug_info.GetAddrSwitch("-mem_start"); | |
75 nexe_mem_base_ = reinterpret_cast<uint64_t>(mem_base); | |
76 void* user_entry_point = debug_info.GetAddrSwitch("-user_entry_pt"); | |
77 printf("TR03.03: NaClAppCreate mem_base=%p entry_point=%p", | |
78 mem_base, | |
79 user_entry_point); | |
80 } else if ("ThreadCreate" == event) { | |
81 thread = new DebuggeeThread(debug_event.pid_, &debug_api_); | |
82 threads_.push_back(thread); | |
83 } | |
84 } | |
85 } | |
86 if (NULL == thread) { | |
87 // it's not NaClApp thread, and we ignore them | |
88 DebuggeeThread thr(debug_event.pid_, &debug_api_); | |
89 thr.OnDebugEvent(debug_event); | |
90 thr.Continue(); | |
91 return false; | |
92 } | |
93 | |
94 // It's a known NaClApp thread. | |
95 // So, what we need to do: | |
96 // 1) change the thread state | |
97 // 2) stop all other threads | |
98 thread->OnDebugEvent(debug_event); | |
99 if (thread->state() != PROCESS_STOPPED) // thread is deed | |
100 DeleteThread(debug_event.pid_); | |
101 else | |
102 StopAllThreads(); | |
103 return true; | |
104 } | |
105 | |
106 void DebuggeeProcess::StopAllThreads() { | |
107 if (stopping_treads_) | |
108 return; | |
109 stopping_treads_ = true; | |
110 ThreadConstIter it = threads_.begin(); | |
111 while (it != threads_.end()) { | |
112 DebuggeeThread* thread = *it; | |
113 if (thread->state() == RUNNING) | |
114 debug_api_.PostSignal(thread->id(), SIGSTOP); | |
115 ++it; | |
116 } | |
117 // Wait till all threads stops. | |
118 time_t end = time(0) + kWatForAllThreadsToStopSecs; | |
119 do { | |
120 if (AllThreadStopped()) | |
121 break; | |
122 DebugEvent debug_event; | |
123 while (debug_api_.WaitForDebugEvent(&debug_event)) | |
124 OnDebugEvent(debug_event); | |
125 | |
126 } while(time(0) < end); | |
127 | |
128 if (!AllThreadStopped()) | |
129 printf("Warning: not all threads stopped.\n"); | |
130 | |
131 stopping_treads_ = false; | |
132 } | |
133 | |
134 bool DebuggeeProcess::AllThreadStopped() { | |
135 ThreadConstIter it = threads_.begin(); | |
136 while (it != threads_.end()) { | |
137 if ((*it)->state() == RUNNING) | |
138 return false; | |
139 ++it; | |
140 } | |
141 return true; | |
142 } | |
143 | |
144 void DebuggeeProcess::Continue(int tid) { | |
145 DebuggeeThread* thread = GetThread(tid); | |
146 if (NULL != thread) | |
147 thread->Continue(); | |
148 | |
149 ThreadConstIter it = threads_.begin(); | |
150 while (it != threads_.end()) { | |
151 (*it)->Continue(); | |
152 ++it; | |
153 } | |
154 } | |
155 | |
156 void DebuggeeProcess::DeleteThread(int tid) { | |
157 ThreadIter it = threads_.begin(); | |
158 while (it != threads_.end()) { | |
159 DebuggeeThread* thread = *it; | |
160 if (tid == thread->id()) { | |
161 delete thread; | |
162 threads_.erase(it); | |
163 break; | |
164 } | |
165 ++it; | |
166 } | |
167 } | |
168 | |
169 } // namespace debug | |
170 | |
OLD | NEW |