File: | tools/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp |
Location: | line 197, column 12 |
Description: | Potential leak of memory pointed to by 'reg_interface' |
1 | //===-- NativeThreadLinux.cpp --------------------------------- -*- C++ -*-===// | |||
2 | // | |||
3 | // The LLVM Compiler Infrastructure | |||
4 | // | |||
5 | // This file is distributed under the University of Illinois Open Source | |||
6 | // License. See LICENSE.TXT for details. | |||
7 | // | |||
8 | //===----------------------------------------------------------------------===// | |||
9 | ||||
10 | #include "NativeThreadLinux.h" | |||
11 | ||||
12 | #include <signal.h> | |||
13 | ||||
14 | #include "NativeProcessLinux.h" | |||
15 | #include "NativeRegisterContextLinux_x86_64.h" | |||
16 | ||||
17 | #include "lldb/Core/Log.h" | |||
18 | #include "lldb/Core/State.h" | |||
19 | #include "lldb/Host/Host.h" | |||
20 | #include "lldb/Host/HostInfo.h" | |||
21 | #include "lldb/Host/HostNativeThread.h" | |||
22 | #include "lldb/lldb-enumerations.h" | |||
23 | #include "lldb/lldb-private-log.h" | |||
24 | ||||
25 | #include "llvm/ADT/SmallString.h" | |||
26 | ||||
27 | #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" | |||
28 | #include "Plugins/Process/Utility/RegisterContextLinux_i386.h" | |||
29 | #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" | |||
30 | #include "Plugins/Process/Utility/RegisterInfoInterface.h" | |||
31 | ||||
32 | using namespace lldb; | |||
33 | using namespace lldb_private; | |||
34 | ||||
35 | namespace | |||
36 | { | |||
37 | void LogThreadStopInfo (Log &log, const ThreadStopInfo &stop_info, const char *const header) | |||
38 | { | |||
39 | switch (stop_info.reason) | |||
40 | { | |||
41 | case eStopReasonSignal: | |||
42 | log.Printf ("%s: %s signal 0x%" PRIx32"x", __FUNCTION__, header, stop_info.details.signal.signo); | |||
43 | return; | |||
44 | case eStopReasonException: | |||
45 | log.Printf ("%s: %s exception type 0x%" PRIx64"l" "x", __FUNCTION__, header, stop_info.details.exception.type); | |||
46 | return; | |||
47 | case eStopReasonExec: | |||
48 | log.Printf ("%s: %s exec, stopping signal 0x%" PRIx32"x", __FUNCTION__, header, stop_info.details.signal.signo); | |||
49 | return; | |||
50 | default: | |||
51 | log.Printf ("%s: %s invalid stop reason %" PRIu32"u", __FUNCTION__, header, static_cast<uint32_t> (stop_info.reason)); | |||
52 | } | |||
53 | } | |||
54 | } | |||
55 | ||||
56 | NativeThreadLinux::NativeThreadLinux (NativeProcessLinux *process, lldb::tid_t tid) : | |||
57 | NativeThreadProtocol (process, tid), | |||
58 | m_state (StateType::eStateInvalid), | |||
59 | m_stop_info (), | |||
60 | m_reg_context_sp () | |||
61 | { | |||
62 | } | |||
63 | ||||
64 | std::string | |||
65 | NativeThreadLinux::GetName() | |||
66 | { | |||
67 | NativeProcessProtocolSP process_sp = m_process_wp.lock (); | |||
68 | if (!process_sp) | |||
69 | return "<unknown: no process>"; | |||
70 | ||||
71 | // const NativeProcessLinux *const process = reinterpret_cast<NativeProcessLinux*> (process_sp->get ()); | |||
72 | llvm::SmallString<32> thread_name; | |||
73 | HostNativeThread::GetName(GetID(), thread_name); | |||
74 | return thread_name.c_str(); | |||
75 | } | |||
76 | ||||
77 | lldb::StateType | |||
78 | NativeThreadLinux::GetState () | |||
79 | { | |||
80 | return m_state; | |||
81 | } | |||
82 | ||||
83 | ||||
84 | bool | |||
85 | NativeThreadLinux::GetStopReason (ThreadStopInfo &stop_info) | |||
86 | { | |||
87 | Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD(1u << 2))); | |||
88 | switch (m_state) | |||
89 | { | |||
90 | case eStateStopped: | |||
91 | case eStateCrashed: | |||
92 | case eStateExited: | |||
93 | case eStateSuspended: | |||
94 | case eStateUnloaded: | |||
95 | if (log) | |||
96 | LogThreadStopInfo (*log, m_stop_info, "m_stop_info in thread:"); | |||
97 | stop_info = m_stop_info; | |||
98 | if (log) | |||
99 | LogThreadStopInfo (*log, stop_info, "returned stop_info:"); | |||
100 | return true; | |||
101 | ||||
102 | case eStateInvalid: | |||
103 | case eStateConnected: | |||
104 | case eStateAttaching: | |||
105 | case eStateLaunching: | |||
106 | case eStateRunning: | |||
107 | case eStateStepping: | |||
108 | case eStateDetached: | |||
109 | if (log) | |||
110 | { | |||
111 | log->Printf ("NativeThreadLinux::%s tid %" PRIu64"l" "u" " in state %s cannot answer stop reason", | |||
112 | __FUNCTION__, GetID (), StateAsCString (m_state)); | |||
113 | } | |||
114 | return false; | |||
115 | } | |||
116 | llvm_unreachable("unhandled StateType!")::llvm::llvm_unreachable_internal("unhandled StateType!", "/tmp/buildd/llvm-toolchain-snapshot-3.6~svn224369/tools/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp" , 116); | |||
117 | } | |||
118 | ||||
119 | lldb_private::NativeRegisterContextSP | |||
120 | NativeThreadLinux::GetRegisterContext () | |||
121 | { | |||
122 | // Return the register context if we already created it. | |||
123 | if (m_reg_context_sp) | |||
| ||||
124 | return m_reg_context_sp; | |||
125 | ||||
126 | // First select the appropriate RegisterInfoInterface. | |||
127 | RegisterInfoInterface *reg_interface = nullptr; | |||
128 | NativeProcessProtocolSP m_process_sp = m_process_wp.lock (); | |||
129 | if (!m_process_sp) | |||
130 | return NativeRegisterContextSP (); | |||
131 | ||||
132 | ArchSpec target_arch; | |||
133 | if (!m_process_sp->GetArchitecture (target_arch)) | |||
134 | return NativeRegisterContextSP (); | |||
135 | ||||
136 | switch (target_arch.GetTriple().getOS()) | |||
137 | { | |||
138 | case llvm::Triple::Linux: | |||
139 | switch (target_arch.GetMachine()) | |||
140 | { | |||
141 | case llvm::Triple::aarch64: | |||
142 | assert((HostInfo::GetArchitecture ().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host")(((HostInfo::GetArchitecture ().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host") ? static_cast <void> (0) : __assert_fail ("(HostInfo::GetArchitecture ().GetAddressByteSize() == 8) && \"Register setting path assumes this is a 64-bit host\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.6~svn224369/tools/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp" , 142, __PRETTY_FUNCTION__)); | |||
143 | reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_arm64(target_arch)); | |||
144 | break; | |||
145 | case llvm::Triple::x86: | |||
146 | case llvm::Triple::x86_64: | |||
147 | if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) | |||
148 | { | |||
149 | // 32-bit hosts run with a RegisterContextLinux_i386 context. | |||
150 | reg_interface = static_cast<RegisterInfoInterface*>(new RegisterContextLinux_i386(target_arch)); | |||
151 | } | |||
152 | else | |||
153 | { | |||
154 | assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) &&(((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host") ? static_cast <void> (0) : __assert_fail ("(HostInfo::GetArchitecture().GetAddressByteSize() == 8) && \"Register setting path assumes this is a 64-bit host\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.6~svn224369/tools/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp" , 155, __PRETTY_FUNCTION__)) | |||
155 | "Register setting path assumes this is a 64-bit host")(((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host") ? static_cast <void> (0) : __assert_fail ("(HostInfo::GetArchitecture().GetAddressByteSize() == 8) && \"Register setting path assumes this is a 64-bit host\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.6~svn224369/tools/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp" , 155, __PRETTY_FUNCTION__)); | |||
156 | // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 register context. | |||
157 | reg_interface = static_cast<RegisterInfoInterface*> (new RegisterContextLinux_x86_64 (target_arch)); | |||
158 | } | |||
159 | break; | |||
160 | default: | |||
161 | break; | |||
162 | } | |||
163 | break; | |||
164 | default: | |||
165 | break; | |||
166 | } | |||
167 | ||||
168 | assert(reg_interface && "OS or CPU not supported!")((reg_interface && "OS or CPU not supported!") ? static_cast <void> (0) : __assert_fail ("reg_interface && \"OS or CPU not supported!\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.6~svn224369/tools/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp" , 168, __PRETTY_FUNCTION__)); | |||
169 | if (!reg_interface) | |||
170 | return NativeRegisterContextSP (); | |||
171 | ||||
172 | // Now create the register context. | |||
173 | switch (target_arch.GetMachine()) | |||
174 | { | |||
175 | #if 0 | |||
176 | case llvm::Triple::mips64: | |||
177 | { | |||
178 | RegisterContextPOSIXProcessMonitor_mips64 *reg_ctx = new RegisterContextPOSIXProcessMonitor_mips64(*this, 0, reg_interface); | |||
179 | m_posix_thread = reg_ctx; | |||
180 | m_reg_context_sp.reset(reg_ctx); | |||
181 | break; | |||
182 | } | |||
183 | #endif | |||
184 | #if 0 | |||
185 | case llvm::Triple::x86: | |||
186 | #endif | |||
187 | case llvm::Triple::x86_64: | |||
188 | { | |||
189 | const uint32_t concrete_frame_idx = 0; | |||
190 | m_reg_context_sp.reset (new NativeRegisterContextLinux_x86_64(*this, concrete_frame_idx, reg_interface)); | |||
191 | break; | |||
192 | } | |||
193 | default: | |||
194 | break; | |||
195 | } | |||
196 | ||||
197 | return m_reg_context_sp; | |||
| ||||
198 | } | |||
199 | ||||
200 | Error | |||
201 | NativeThreadLinux::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) | |||
202 | { | |||
203 | // TODO implement | |||
204 | return Error ("not implemented"); | |||
205 | } | |||
206 | ||||
207 | Error | |||
208 | NativeThreadLinux::RemoveWatchpoint (lldb::addr_t addr) | |||
209 | { | |||
210 | // TODO implement | |||
211 | return Error ("not implemented"); | |||
212 | } | |||
213 | ||||
214 | void | |||
215 | NativeThreadLinux::SetLaunching () | |||
216 | { | |||
217 | const StateType new_state = StateType::eStateLaunching; | |||
218 | MaybeLogStateChange (new_state); | |||
219 | m_state = new_state; | |||
220 | ||||
221 | // Also mark it as stopped since launching temporarily stops the newly created thread | |||
222 | // in the ptrace machinery. | |||
223 | m_stop_info.reason = StopReason::eStopReasonSignal; | |||
224 | m_stop_info.details.signal.signo = SIGSTOP19; | |||
225 | } | |||
226 | ||||
227 | ||||
228 | void | |||
229 | NativeThreadLinux::SetRunning () | |||
230 | { | |||
231 | const StateType new_state = StateType::eStateRunning; | |||
232 | MaybeLogStateChange (new_state); | |||
233 | m_state = new_state; | |||
234 | ||||
235 | m_stop_info.reason = StopReason::eStopReasonNone; | |||
236 | } | |||
237 | ||||
238 | void | |||
239 | NativeThreadLinux::SetStepping () | |||
240 | { | |||
241 | const StateType new_state = StateType::eStateStepping; | |||
242 | MaybeLogStateChange (new_state); | |||
243 | m_state = new_state; | |||
244 | ||||
245 | m_stop_info.reason = StopReason::eStopReasonNone; | |||
246 | } | |||
247 | ||||
248 | void | |||
249 | NativeThreadLinux::SetStoppedBySignal (uint32_t signo) | |||
250 | { | |||
251 | Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD(1u << 2))); | |||
252 | if (log) | |||
253 | log->Printf ("NativeThreadLinux::%s called with signal 0x%" PRIx32"x", __FUNCTION__, signo); | |||
254 | ||||
255 | const StateType new_state = StateType::eStateStopped; | |||
256 | MaybeLogStateChange (new_state); | |||
257 | m_state = new_state; | |||
258 | ||||
259 | m_stop_info.reason = StopReason::eStopReasonSignal; | |||
260 | m_stop_info.details.signal.signo = signo; | |||
261 | } | |||
262 | ||||
263 | bool | |||
264 | NativeThreadLinux::IsStopped (int *signo) | |||
265 | { | |||
266 | if (!StateIsStoppedState (m_state, false)) | |||
267 | return false; | |||
268 | ||||
269 | // If we are stopped by a signal, return the signo. | |||
270 | if (signo && | |||
271 | m_state == StateType::eStateStopped && | |||
272 | m_stop_info.reason == StopReason::eStopReasonSignal) | |||
273 | { | |||
274 | *signo = m_stop_info.details.signal.signo; | |||
275 | } | |||
276 | ||||
277 | // Regardless, we are stopped. | |||
278 | return true; | |||
279 | } | |||
280 | ||||
281 | ||||
282 | void | |||
283 | NativeThreadLinux::SetStoppedByExec () | |||
284 | { | |||
285 | Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD(1u << 2))); | |||
286 | if (log) | |||
287 | log->Printf ("NativeThreadLinux::%s()", __FUNCTION__); | |||
288 | ||||
289 | const StateType new_state = StateType::eStateStopped; | |||
290 | MaybeLogStateChange (new_state); | |||
291 | m_state = new_state; | |||
292 | ||||
293 | m_stop_info.reason = StopReason::eStopReasonExec; | |||
294 | m_stop_info.details.signal.signo = SIGSTOP19; | |||
295 | } | |||
296 | ||||
297 | void | |||
298 | NativeThreadLinux::SetStoppedByBreakpoint () | |||
299 | { | |||
300 | const StateType new_state = StateType::eStateStopped; | |||
301 | MaybeLogStateChange (new_state); | |||
302 | m_state = new_state; | |||
303 | ||||
304 | m_stop_info.reason = StopReason::eStopReasonSignal; | |||
305 | m_stop_info.details.signal.signo = SIGTRAP5; | |||
306 | } | |||
307 | ||||
308 | bool | |||
309 | NativeThreadLinux::IsStoppedAtBreakpoint () | |||
310 | { | |||
311 | // Are we stopped? If not, this can't be a breakpoint. | |||
312 | if (GetState () != StateType::eStateStopped) | |||
313 | return false; | |||
314 | ||||
315 | // Was the stop reason a signal with signal number SIGTRAP? If not, not a breakpoint. | |||
316 | return (m_stop_info.reason == StopReason::eStopReasonSignal) && | |||
317 | (m_stop_info.details.signal.signo == SIGTRAP5); | |||
318 | } | |||
319 | ||||
320 | void | |||
321 | NativeThreadLinux::SetCrashedWithException (uint64_t exception_type, lldb::addr_t exception_addr) | |||
322 | { | |||
323 | const StateType new_state = StateType::eStateCrashed; | |||
324 | MaybeLogStateChange (new_state); | |||
325 | m_state = new_state; | |||
326 | ||||
327 | m_stop_info.reason = StopReason::eStopReasonException; | |||
328 | m_stop_info.details.exception.type = exception_type; | |||
329 | m_stop_info.details.exception.data_count = 1; | |||
330 | m_stop_info.details.exception.data[0] = exception_addr; | |||
331 | } | |||
332 | ||||
333 | ||||
334 | void | |||
335 | NativeThreadLinux::SetSuspended () | |||
336 | { | |||
337 | const StateType new_state = StateType::eStateSuspended; | |||
338 | MaybeLogStateChange (new_state); | |||
339 | m_state = new_state; | |||
340 | ||||
341 | // FIXME what makes sense here? Do we need a suspended StopReason? | |||
342 | m_stop_info.reason = StopReason::eStopReasonNone; | |||
343 | } | |||
344 | ||||
345 | void | |||
346 | NativeThreadLinux::SetExited () | |||
347 | { | |||
348 | const StateType new_state = StateType::eStateExited; | |||
349 | MaybeLogStateChange (new_state); | |||
350 | m_state = new_state; | |||
351 | ||||
352 | m_stop_info.reason = StopReason::eStopReasonThreadExiting; | |||
353 | } | |||
354 | ||||
355 | void | |||
356 | NativeThreadLinux::MaybeLogStateChange (lldb::StateType new_state) | |||
357 | { | |||
358 | Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD(1u << 2))); | |||
359 | // If we're not logging, we're done. | |||
360 | if (!log) | |||
361 | return; | |||
362 | ||||
363 | // If this is a state change to the same state, we're done. | |||
364 | lldb::StateType old_state = m_state; | |||
365 | if (new_state == old_state) | |||
366 | return; | |||
367 | ||||
368 | NativeProcessProtocolSP m_process_sp = m_process_wp.lock (); | |||
369 | lldb::pid_t pid = m_process_sp ? m_process_sp->GetID () : LLDB_INVALID_PROCESS_ID0; | |||
370 | ||||
371 | // Log it. | |||
372 | log->Printf ("NativeThreadLinux: thread (pid=%" PRIu64"l" "u" ", tid=%" PRIu64"l" "u" ") changing from state %s to %s", pid, GetID (), StateAsCString (old_state), StateAsCString (new_state)); | |||
373 | } | |||
374 | ||||
375 | uint32_t | |||
376 | NativeThreadLinux::TranslateStopInfoToGdbSignal (const ThreadStopInfo &stop_info) const | |||
377 | { | |||
378 | switch (stop_info.reason) | |||
379 | { | |||
380 | case eStopReasonSignal: | |||
381 | // No translation. | |||
382 | return stop_info.details.signal.signo; | |||
383 | ||||
384 | case eStopReasonException: | |||
385 | { | |||
386 | Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD(1u << 2))); | |||
387 | // FIXME I think the eStopReasonException is a xnu/Mach exception, which we | |||
388 | // shouldn't see on Linux. | |||
389 | // No translation. | |||
390 | if (log) | |||
391 | log->Printf ("NativeThreadLinux::%s saw an exception stop type (signo %" | |||
392 | PRIu64"l" "u" "), not expecting to see exceptions on Linux", | |||
393 | __FUNCTION__, | |||
394 | stop_info.details.exception.type); | |||
395 | return static_cast<uint32_t> (stop_info.details.exception.type); | |||
396 | } | |||
397 | ||||
398 | default: | |||
399 | assert (0 && "unexpected stop_info.reason found")((0 && "unexpected stop_info.reason found") ? static_cast <void> (0) : __assert_fail ("0 && \"unexpected stop_info.reason found\"" , "/tmp/buildd/llvm-toolchain-snapshot-3.6~svn224369/tools/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp" , 399, __PRETTY_FUNCTION__)); | |||
400 | return 0; | |||
401 | } | |||
402 | } | |||
403 |