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
44using namespace lldb;
45using namespace lldb_private;
46
47// Construct a Thread object with given data
48ThreadElfCore::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
53ThreadElfCore::~ThreadElfCore() { DestroyThread(); }
54
55void ThreadElfCore::RefreshStateAfterStop() {
56 GetRegisterContext()->InvalidateIfNeeded(force: false);
57}
58
59RegisterContextSP 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
66RegisterContextSP
67ThreadElfCore::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
231bool 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
242ELFLinuxPrStatus::ELFLinuxPrStatus() {
243 memset(s: this, c: 0, n: sizeof(ELFLinuxPrStatus));
244}
245
246size_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
272Status ELFLinuxPrStatus::Parse(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
316ELFLinuxPrPsInfo::ELFLinuxPrPsInfo() {
317 memset(s: this, c: 0, n: sizeof(ELFLinuxPrPsInfo));
318}
319
320size_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
341Status ELFLinuxPrPsInfo::Parse(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
392ELFLinuxSigInfo::ELFLinuxSigInfo() { memset(s: this, c: 0, n: sizeof(ELFLinuxSigInfo)); }
393
394size_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
409Status ELFLinuxSigInfo::Parse(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

source code of lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp