1 | //===-- ThreadElfCore.cpp -------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "lldb/Target/RegisterContext.h" |
10 | #include "lldb/Target/StopInfo.h" |
11 | #include "lldb/Target/Target.h" |
12 | #include "lldb/Target/Unwind.h" |
13 | #include "lldb/Utility/DataExtractor.h" |
14 | #include "lldb/Utility/LLDBLog.h" |
15 | #include "lldb/Utility/Log.h" |
16 | |
17 | #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" |
18 | #include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" |
19 | #include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" |
20 | #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" |
21 | #include "Plugins/Process/Utility/RegisterContextLinux_i386.h" |
22 | #include "Plugins/Process/Utility/RegisterContextLinux_s390x.h" |
23 | #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" |
24 | #include "Plugins/Process/Utility/RegisterContextNetBSD_i386.h" |
25 | #include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h" |
26 | #include "Plugins/Process/Utility/RegisterContextOpenBSD_i386.h" |
27 | #include "Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h" |
28 | #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" |
29 | #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" |
30 | #include "Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.h" |
31 | #include "ProcessElfCore.h" |
32 | #include "RegisterContextLinuxCore_x86_64.h" |
33 | #include "RegisterContextPOSIXCore_arm.h" |
34 | #include "RegisterContextPOSIXCore_arm64.h" |
35 | #include "RegisterContextPOSIXCore_mips64.h" |
36 | #include "RegisterContextPOSIXCore_powerpc.h" |
37 | #include "RegisterContextPOSIXCore_ppc64le.h" |
38 | #include "RegisterContextPOSIXCore_s390x.h" |
39 | #include "RegisterContextPOSIXCore_x86_64.h" |
40 | #include "ThreadElfCore.h" |
41 | |
42 | #include <memory> |
43 | |
44 | using namespace lldb; |
45 | using namespace lldb_private; |
46 | |
47 | // Construct a Thread object with given data |
48 | ThreadElfCore::ThreadElfCore(Process &process, const ThreadData &td) |
49 | : Thread(process, td.tid), m_thread_name(td.name), m_thread_reg_ctx_sp(), |
50 | m_signo(td.signo), m_code(td.code), m_gpregset_data(td.gpregset), |
51 | m_notes(td.notes) {} |
52 | |
53 | ThreadElfCore::~ThreadElfCore() { DestroyThread(); } |
54 | |
55 | void ThreadElfCore::RefreshStateAfterStop() { |
56 | GetRegisterContext()->InvalidateIfNeeded(force: false); |
57 | } |
58 | |
59 | RegisterContextSP ThreadElfCore::GetRegisterContext() { |
60 | if (!m_reg_context_sp) { |
61 | m_reg_context_sp = CreateRegisterContextForFrame(frame: nullptr); |
62 | } |
63 | return m_reg_context_sp; |
64 | } |
65 | |
66 | RegisterContextSP |
67 | ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { |
68 | RegisterContextSP reg_ctx_sp; |
69 | uint32_t concrete_frame_idx = 0; |
70 | Log *log = GetLog(mask: LLDBLog::Thread); |
71 | |
72 | if (frame) |
73 | concrete_frame_idx = frame->GetConcreteFrameIndex(); |
74 | |
75 | bool is_linux = false; |
76 | if (concrete_frame_idx == 0) { |
77 | if (m_thread_reg_ctx_sp) |
78 | return m_thread_reg_ctx_sp; |
79 | |
80 | ProcessElfCore *process = static_cast<ProcessElfCore *>(GetProcess().get()); |
81 | ArchSpec arch = process->GetArchitecture(); |
82 | RegisterInfoInterface *reg_interface = nullptr; |
83 | |
84 | switch (arch.GetTriple().getOS()) { |
85 | case llvm::Triple::FreeBSD: { |
86 | switch (arch.GetMachine()) { |
87 | case llvm::Triple::aarch64: |
88 | case llvm::Triple::arm: |
89 | break; |
90 | case llvm::Triple::ppc: |
91 | reg_interface = new RegisterContextFreeBSD_powerpc32(arch); |
92 | break; |
93 | case llvm::Triple::ppc64: |
94 | reg_interface = new RegisterContextFreeBSD_powerpc64(arch); |
95 | break; |
96 | case llvm::Triple::mips64: |
97 | reg_interface = new RegisterContextFreeBSD_mips64(arch); |
98 | break; |
99 | case llvm::Triple::x86: |
100 | reg_interface = new RegisterContextFreeBSD_i386(arch); |
101 | break; |
102 | case llvm::Triple::x86_64: |
103 | reg_interface = new RegisterContextFreeBSD_x86_64(arch); |
104 | break; |
105 | default: |
106 | break; |
107 | } |
108 | break; |
109 | } |
110 | |
111 | case llvm::Triple::NetBSD: { |
112 | switch (arch.GetMachine()) { |
113 | case llvm::Triple::aarch64: |
114 | break; |
115 | case llvm::Triple::x86: |
116 | reg_interface = new RegisterContextNetBSD_i386(arch); |
117 | break; |
118 | case llvm::Triple::x86_64: |
119 | reg_interface = new RegisterContextNetBSD_x86_64(arch); |
120 | break; |
121 | default: |
122 | break; |
123 | } |
124 | break; |
125 | } |
126 | |
127 | case llvm::Triple::Linux: { |
128 | is_linux = true; |
129 | switch (arch.GetMachine()) { |
130 | case llvm::Triple::aarch64: |
131 | break; |
132 | case llvm::Triple::ppc64le: |
133 | reg_interface = new RegisterInfoPOSIX_ppc64le(arch); |
134 | break; |
135 | case llvm::Triple::systemz: |
136 | reg_interface = new RegisterContextLinux_s390x(arch); |
137 | break; |
138 | case llvm::Triple::x86: |
139 | reg_interface = new RegisterContextLinux_i386(arch); |
140 | break; |
141 | case llvm::Triple::x86_64: |
142 | reg_interface = new RegisterContextLinux_x86_64(arch); |
143 | break; |
144 | default: |
145 | break; |
146 | } |
147 | break; |
148 | } |
149 | |
150 | case llvm::Triple::OpenBSD: { |
151 | switch (arch.GetMachine()) { |
152 | case llvm::Triple::aarch64: |
153 | break; |
154 | case llvm::Triple::x86: |
155 | reg_interface = new RegisterContextOpenBSD_i386(arch); |
156 | break; |
157 | case llvm::Triple::x86_64: |
158 | reg_interface = new RegisterContextOpenBSD_x86_64(arch); |
159 | break; |
160 | default: |
161 | break; |
162 | } |
163 | break; |
164 | } |
165 | |
166 | default: |
167 | break; |
168 | } |
169 | |
170 | if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64 && |
171 | arch.GetMachine() != llvm::Triple::arm) { |
172 | LLDB_LOGF(log, "elf-core::%s:: Architecture(%d) or OS(%d) not supported" , |
173 | __FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS()); |
174 | assert(false && "Architecture or OS not supported" ); |
175 | } |
176 | |
177 | switch (arch.GetMachine()) { |
178 | case llvm::Triple::aarch64: |
179 | m_thread_reg_ctx_sp = RegisterContextCorePOSIX_arm64::Create( |
180 | thread&: *this, arch, gpregset: m_gpregset_data, notes: m_notes); |
181 | break; |
182 | case llvm::Triple::arm: |
183 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_arm>( |
184 | args&: *this, args: std::make_unique<RegisterInfoPOSIX_arm>(args&: arch), args&: m_gpregset_data, |
185 | args&: m_notes); |
186 | break; |
187 | case llvm::Triple::mipsel: |
188 | case llvm::Triple::mips: |
189 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_mips64>( |
190 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
191 | break; |
192 | case llvm::Triple::mips64: |
193 | case llvm::Triple::mips64el: |
194 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_mips64>( |
195 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
196 | break; |
197 | case llvm::Triple::ppc: |
198 | case llvm::Triple::ppc64: |
199 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_powerpc>( |
200 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
201 | break; |
202 | case llvm::Triple::ppc64le: |
203 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_ppc64le>( |
204 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
205 | break; |
206 | case llvm::Triple::systemz: |
207 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_s390x>( |
208 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
209 | break; |
210 | case llvm::Triple::x86: |
211 | case llvm::Triple::x86_64: |
212 | if (is_linux) { |
213 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextLinuxCore_x86_64>( |
214 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
215 | } else { |
216 | m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_x86_64>( |
217 | args&: *this, args&: reg_interface, args&: m_gpregset_data, args&: m_notes); |
218 | } |
219 | break; |
220 | default: |
221 | break; |
222 | } |
223 | |
224 | reg_ctx_sp = m_thread_reg_ctx_sp; |
225 | } else { |
226 | reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); |
227 | } |
228 | return reg_ctx_sp; |
229 | } |
230 | |
231 | bool ThreadElfCore::CalculateStopInfo() { |
232 | ProcessSP process_sp(GetProcess()); |
233 | if (!process_sp) |
234 | return false; |
235 | |
236 | SetStopInfo(StopInfo::CreateStopReasonWithSignal( |
237 | thread&: *this, signo: m_signo, /*description=*/nullptr, code: m_code)); |
238 | return true; |
239 | } |
240 | |
241 | // Parse PRSTATUS from NOTE entry |
242 | ELFLinuxPrStatus::ELFLinuxPrStatus() { |
243 | memset(s: this, c: 0, n: sizeof(ELFLinuxPrStatus)); |
244 | } |
245 | |
246 | size_t ELFLinuxPrStatus::GetSize(const lldb_private::ArchSpec &arch) { |
247 | constexpr size_t mips_linux_pr_status_size_o32 = 96; |
248 | constexpr size_t mips_linux_pr_status_size_n32 = 72; |
249 | constexpr size_t num_ptr_size_members = 10; |
250 | if (arch.IsMIPS()) { |
251 | std::string abi = arch.GetTargetABI(); |
252 | assert(!abi.empty() && "ABI is not set" ); |
253 | if (!abi.compare(s: "n64" )) |
254 | return sizeof(ELFLinuxPrStatus); |
255 | else if (!abi.compare(s: "o32" )) |
256 | return mips_linux_pr_status_size_o32; |
257 | // N32 ABI |
258 | return mips_linux_pr_status_size_n32; |
259 | } |
260 | switch (arch.GetCore()) { |
261 | case lldb_private::ArchSpec::eCore_x86_32_i386: |
262 | case lldb_private::ArchSpec::eCore_x86_32_i486: |
263 | return 72; |
264 | default: |
265 | if (arch.GetAddressByteSize() == 8) |
266 | return sizeof(ELFLinuxPrStatus); |
267 | else |
268 | return sizeof(ELFLinuxPrStatus) - num_ptr_size_members * 4; |
269 | } |
270 | } |
271 | |
272 | Status ELFLinuxPrStatus::(const DataExtractor &data, |
273 | const ArchSpec &arch) { |
274 | Status error; |
275 | if (GetSize(arch) > data.GetByteSize()) { |
276 | error.SetErrorStringWithFormat( |
277 | "NT_PRSTATUS size should be %zu, but the remaining bytes are: %" PRIu64, |
278 | GetSize(arch), data.GetByteSize()); |
279 | return error; |
280 | } |
281 | |
282 | // Read field by field to correctly account for endianess of both the core |
283 | // dump and the platform running lldb. |
284 | offset_t offset = 0; |
285 | si_signo = data.GetU32(offset_ptr: &offset); |
286 | si_code = data.GetU32(offset_ptr: &offset); |
287 | si_errno = data.GetU32(offset_ptr: &offset); |
288 | |
289 | pr_cursig = data.GetU16(offset_ptr: &offset); |
290 | offset += 2; // pad |
291 | |
292 | pr_sigpend = data.GetAddress(offset_ptr: &offset); |
293 | pr_sighold = data.GetAddress(offset_ptr: &offset); |
294 | |
295 | pr_pid = data.GetU32(offset_ptr: &offset); |
296 | pr_ppid = data.GetU32(offset_ptr: &offset); |
297 | pr_pgrp = data.GetU32(offset_ptr: &offset); |
298 | pr_sid = data.GetU32(offset_ptr: &offset); |
299 | |
300 | pr_utime.tv_sec = data.GetAddress(offset_ptr: &offset); |
301 | pr_utime.tv_usec = data.GetAddress(offset_ptr: &offset); |
302 | |
303 | pr_stime.tv_sec = data.GetAddress(offset_ptr: &offset); |
304 | pr_stime.tv_usec = data.GetAddress(offset_ptr: &offset); |
305 | |
306 | pr_cutime.tv_sec = data.GetAddress(offset_ptr: &offset); |
307 | pr_cutime.tv_usec = data.GetAddress(offset_ptr: &offset); |
308 | |
309 | pr_cstime.tv_sec = data.GetAddress(offset_ptr: &offset); |
310 | pr_cstime.tv_usec = data.GetAddress(offset_ptr: &offset); |
311 | |
312 | return error; |
313 | } |
314 | |
315 | // Parse PRPSINFO from NOTE entry |
316 | ELFLinuxPrPsInfo::ELFLinuxPrPsInfo() { |
317 | memset(s: this, c: 0, n: sizeof(ELFLinuxPrPsInfo)); |
318 | } |
319 | |
320 | size_t ELFLinuxPrPsInfo::GetSize(const lldb_private::ArchSpec &arch) { |
321 | constexpr size_t mips_linux_pr_psinfo_size_o32_n32 = 128; |
322 | if (arch.IsMIPS()) { |
323 | uint8_t address_byte_size = arch.GetAddressByteSize(); |
324 | if (address_byte_size == 8) |
325 | return sizeof(ELFLinuxPrPsInfo); |
326 | return mips_linux_pr_psinfo_size_o32_n32; |
327 | } |
328 | |
329 | switch (arch.GetCore()) { |
330 | case lldb_private::ArchSpec::eCore_s390x_generic: |
331 | case lldb_private::ArchSpec::eCore_x86_64_x86_64: |
332 | return sizeof(ELFLinuxPrPsInfo); |
333 | case lldb_private::ArchSpec::eCore_x86_32_i386: |
334 | case lldb_private::ArchSpec::eCore_x86_32_i486: |
335 | return 124; |
336 | default: |
337 | return 0; |
338 | } |
339 | } |
340 | |
341 | Status ELFLinuxPrPsInfo::(const DataExtractor &data, |
342 | const ArchSpec &arch) { |
343 | Status error; |
344 | ByteOrder byteorder = data.GetByteOrder(); |
345 | if (GetSize(arch) > data.GetByteSize()) { |
346 | error.SetErrorStringWithFormat( |
347 | "NT_PRPSINFO size should be %zu, but the remaining bytes are: %" PRIu64, |
348 | GetSize(arch), data.GetByteSize()); |
349 | return error; |
350 | } |
351 | size_t size = 0; |
352 | offset_t offset = 0; |
353 | |
354 | pr_state = data.GetU8(offset_ptr: &offset); |
355 | pr_sname = data.GetU8(offset_ptr: &offset); |
356 | pr_zomb = data.GetU8(offset_ptr: &offset); |
357 | pr_nice = data.GetU8(offset_ptr: &offset); |
358 | if (data.GetAddressByteSize() == 8) { |
359 | // Word align the next field on 64 bit. |
360 | offset += 4; |
361 | } |
362 | |
363 | pr_flag = data.GetAddress(offset_ptr: &offset); |
364 | |
365 | if (arch.IsMIPS()) { |
366 | // The pr_uid and pr_gid is always 32 bit irrespective of platforms |
367 | pr_uid = data.GetU32(offset_ptr: &offset); |
368 | pr_gid = data.GetU32(offset_ptr: &offset); |
369 | } else { |
370 | // 16 bit on 32 bit platforms, 32 bit on 64 bit platforms |
371 | pr_uid = data.GetMaxU64(offset_ptr: &offset, byte_size: data.GetAddressByteSize() >> 1); |
372 | pr_gid = data.GetMaxU64(offset_ptr: &offset, byte_size: data.GetAddressByteSize() >> 1); |
373 | } |
374 | |
375 | pr_pid = data.GetU32(offset_ptr: &offset); |
376 | pr_ppid = data.GetU32(offset_ptr: &offset); |
377 | pr_pgrp = data.GetU32(offset_ptr: &offset); |
378 | pr_sid = data.GetU32(offset_ptr: &offset); |
379 | |
380 | size = 16; |
381 | data.ExtractBytes(offset, length: size, dst_byte_order: byteorder, dst: pr_fname); |
382 | offset += size; |
383 | |
384 | size = 80; |
385 | data.ExtractBytes(offset, length: size, dst_byte_order: byteorder, dst: pr_psargs); |
386 | offset += size; |
387 | |
388 | return error; |
389 | } |
390 | |
391 | // Parse SIGINFO from NOTE entry |
392 | ELFLinuxSigInfo::ELFLinuxSigInfo() { memset(s: this, c: 0, n: sizeof(ELFLinuxSigInfo)); } |
393 | |
394 | size_t ELFLinuxSigInfo::GetSize(const lldb_private::ArchSpec &arch) { |
395 | if (arch.IsMIPS()) |
396 | return sizeof(ELFLinuxSigInfo); |
397 | switch (arch.GetCore()) { |
398 | case lldb_private::ArchSpec::eCore_x86_64_x86_64: |
399 | return sizeof(ELFLinuxSigInfo); |
400 | case lldb_private::ArchSpec::eCore_s390x_generic: |
401 | case lldb_private::ArchSpec::eCore_x86_32_i386: |
402 | case lldb_private::ArchSpec::eCore_x86_32_i486: |
403 | return 12; |
404 | default: |
405 | return 0; |
406 | } |
407 | } |
408 | |
409 | Status ELFLinuxSigInfo::(const DataExtractor &data, const ArchSpec &arch) { |
410 | Status error; |
411 | if (GetSize(arch) > data.GetByteSize()) { |
412 | error.SetErrorStringWithFormat( |
413 | "NT_SIGINFO size should be %zu, but the remaining bytes are: %" PRIu64, |
414 | GetSize(arch), data.GetByteSize()); |
415 | return error; |
416 | } |
417 | |
418 | // Parsing from a 32 bit ELF core file, and populating/reusing the structure |
419 | // properly, because the struct is for the 64 bit version |
420 | offset_t offset = 0; |
421 | si_signo = data.GetU32(offset_ptr: &offset); |
422 | si_errno = data.GetU32(offset_ptr: &offset); |
423 | si_code = data.GetU32(offset_ptr: &offset); |
424 | |
425 | return error; |
426 | } |
427 | |