Bug Summary

File:build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
Warning:line 668, column 13
Value stored to 'had_nt_regs' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ProcessElfCore.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-15/lib/clang/15.0.0 -isystem /usr/include/libxml2 -D HAVE_ROUND -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/lldb/source/Plugins/Process/elf-core -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/lldb/source/Plugins/Process/elf-core -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/lldb/include -I tools/lldb/include -I include -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/include -I /usr/include/python3.9 -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/clang/include -I tools/lldb/../clang/include -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/lldb/source -I tools/lldb/source -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-15/lib/clang/15.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -O3 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-strict-aliasing -Wno-stringop-truncation -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-04-20-140412-16051-1 -x c++ /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
1//===-- ProcessElfCore.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 <cstdlib>
10
11#include <memory>
12#include <mutex>
13
14#include "lldb/Core/Module.h"
15#include "lldb/Core/ModuleSpec.h"
16#include "lldb/Core/PluginManager.h"
17#include "lldb/Core/Section.h"
18#include "lldb/Target/DynamicLoader.h"
19#include "lldb/Target/MemoryRegionInfo.h"
20#include "lldb/Target/Target.h"
21#include "lldb/Target/UnixSignals.h"
22#include "lldb/Utility/DataBufferHeap.h"
23#include "lldb/Utility/LLDBLog.h"
24#include "lldb/Utility/Log.h"
25#include "lldb/Utility/State.h"
26
27#include "llvm/BinaryFormat/ELF.h"
28#include "llvm/Support/Threading.h"
29
30#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
31#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
32#include "Plugins/Process/elf-core/RegisterUtilities.h"
33#include "ProcessElfCore.h"
34#include "ThreadElfCore.h"
35
36using namespace lldb_private;
37namespace ELF = llvm::ELF;
38
39LLDB_PLUGIN_DEFINE(ProcessElfCore)namespace lldb_private { void lldb_initialize_ProcessElfCore(
) { ProcessElfCore::Initialize(); } void lldb_terminate_ProcessElfCore
() { ProcessElfCore::Terminate(); } }
40
41llvm::StringRef ProcessElfCore::GetPluginDescriptionStatic() {
42 return "ELF core dump plug-in.";
43}
44
45void ProcessElfCore::Terminate() {
46 PluginManager::UnregisterPlugin(ProcessElfCore::CreateInstance);
47}
48
49lldb::ProcessSP ProcessElfCore::CreateInstance(lldb::TargetSP target_sp,
50 lldb::ListenerSP listener_sp,
51 const FileSpec *crash_file,
52 bool can_connect) {
53 lldb::ProcessSP process_sp;
54 if (crash_file && !can_connect) {
55 // Read enough data for a ELF32 header or ELF64 header Note: Here we care
56 // about e_type field only, so it is safe to ignore possible presence of
57 // the header extension.
58 const size_t header_size = sizeof(llvm::ELF::Elf64_Ehdr);
59
60 auto data_sp = FileSystem::Instance().CreateDataBuffer(
61 crash_file->GetPath(), header_size, 0);
62 if (data_sp && data_sp->GetByteSize() == header_size &&
63 elf::ELFHeader::MagicBytesMatch(data_sp->GetBytes())) {
64 elf::ELFHeader elf_header;
65 DataExtractor data(data_sp, lldb::eByteOrderLittle, 4);
66 lldb::offset_t data_offset = 0;
67 if (elf_header.Parse(data, &data_offset)) {
68 // Check whether we're dealing with a raw FreeBSD "full memory dump"
69 // ELF vmcore that needs to be handled via FreeBSDKernel plugin instead.
70 if (elf_header.e_ident[7] == 0xFF && elf_header.e_version == 0)
71 return process_sp;
72 if (elf_header.e_type == llvm::ELF::ET_CORE)
73 process_sp = std::make_shared<ProcessElfCore>(target_sp, listener_sp,
74 *crash_file);
75 }
76 }
77 }
78 return process_sp;
79}
80
81bool ProcessElfCore::CanDebug(lldb::TargetSP target_sp,
82 bool plugin_specified_by_name) {
83 // For now we are just making sure the file exists for a given module
84 if (!m_core_module_sp && FileSystem::Instance().Exists(m_core_file)) {
85 ModuleSpec core_module_spec(m_core_file, target_sp->GetArchitecture());
86 Status error(ModuleList::GetSharedModule(core_module_spec, m_core_module_sp,
87 nullptr, nullptr, nullptr));
88 if (m_core_module_sp) {
89 ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
90 if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile)
91 return true;
92 }
93 }
94 return false;
95}
96
97// ProcessElfCore constructor
98ProcessElfCore::ProcessElfCore(lldb::TargetSP target_sp,
99 lldb::ListenerSP listener_sp,
100 const FileSpec &core_file)
101 : PostMortemProcess(target_sp, listener_sp), m_core_file(core_file) {}
102
103// Destructor
104ProcessElfCore::~ProcessElfCore() {
105 Clear();
106 // We need to call finalize on the process before destroying ourselves to
107 // make sure all of the broadcaster cleanup goes as planned. If we destruct
108 // this class, then Process::~Process() might have problems trying to fully
109 // destroy the broadcaster.
110 Finalize();
111}
112
113lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment(
114 const elf::ELFProgramHeader &header) {
115 const lldb::addr_t addr = header.p_vaddr;
116 FileRange file_range(header.p_offset, header.p_filesz);
117 VMRangeToFileOffset::Entry range_entry(addr, header.p_memsz, file_range);
118
119 // Only add to m_core_aranges if the file size is non zero. Some core files
120 // have PT_LOAD segments for all address ranges, but set f_filesz to zero for
121 // the .text sections since they can be retrieved from the object files.
122 if (header.p_filesz > 0) {
123 VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back();
124 if (last_entry && last_entry->GetRangeEnd() == range_entry.GetRangeBase() &&
125 last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase() &&
126 last_entry->GetByteSize() == last_entry->data.GetByteSize()) {
127 last_entry->SetRangeEnd(range_entry.GetRangeEnd());
128 last_entry->data.SetRangeEnd(range_entry.data.GetRangeEnd());
129 } else {
130 m_core_aranges.Append(range_entry);
131 }
132 }
133 // Keep a separate map of permissions that that isn't coalesced so all ranges
134 // are maintained.
135 const uint32_t permissions =
136 ((header.p_flags & llvm::ELF::PF_R) ? lldb::ePermissionsReadable : 0u) |
137 ((header.p_flags & llvm::ELF::PF_W) ? lldb::ePermissionsWritable : 0u) |
138 ((header.p_flags & llvm::ELF::PF_X) ? lldb::ePermissionsExecutable : 0u);
139
140 m_core_range_infos.Append(
141 VMRangeToPermissions::Entry(addr, header.p_memsz, permissions));
142
143 return addr;
144}
145
146// Process Control
147Status ProcessElfCore::DoLoadCore() {
148 Status error;
149 if (!m_core_module_sp) {
150 error.SetErrorString("invalid core module");
151 return error;
152 }
153
154 ObjectFileELF *core = (ObjectFileELF *)(m_core_module_sp->GetObjectFile());
155 if (core == nullptr) {
156 error.SetErrorString("invalid core object file");
157 return error;
158 }
159
160 llvm::ArrayRef<elf::ELFProgramHeader> segments = core->ProgramHeaders();
161 if (segments.size() == 0) {
162 error.SetErrorString("core file has no segments");
163 return error;
164 }
165
166 SetCanJIT(false);
167
168 m_thread_data_valid = true;
169
170 bool ranges_are_sorted = true;
171 lldb::addr_t vm_addr = 0;
172 /// Walk through segments and Thread and Address Map information.
173 /// PT_NOTE - Contains Thread and Register information
174 /// PT_LOAD - Contains a contiguous range of Process Address Space
175 for (const elf::ELFProgramHeader &H : segments) {
176 DataExtractor data = core->GetSegmentData(H);
177
178 // Parse thread contexts and auxv structure
179 if (H.p_type == llvm::ELF::PT_NOTE) {
180 if (llvm::Error error = ParseThreadContextsFromNoteSegment(H, data))
181 return Status(std::move(error));
182 }
183 // PT_LOAD segments contains address map
184 if (H.p_type == llvm::ELF::PT_LOAD) {
185 lldb::addr_t last_addr = AddAddressRangeFromLoadSegment(H);
186 if (vm_addr > last_addr)
187 ranges_are_sorted = false;
188 vm_addr = last_addr;
189 }
190 }
191
192 if (!ranges_are_sorted) {
193 m_core_aranges.Sort();
194 m_core_range_infos.Sort();
195 }
196
197 // Even if the architecture is set in the target, we need to override it to
198 // match the core file which is always single arch.
199 ArchSpec arch(m_core_module_sp->GetArchitecture());
200
201 ArchSpec target_arch = GetTarget().GetArchitecture();
202 ArchSpec core_arch(m_core_module_sp->GetArchitecture());
203 target_arch.MergeFrom(core_arch);
204 GetTarget().SetArchitecture(target_arch);
205
206 SetUnixSignals(UnixSignals::Create(GetArchitecture()));
207
208 // Ensure we found at least one thread that was stopped on a signal.
209 bool siginfo_signal_found = false;
210 bool prstatus_signal_found = false;
211 // Check we found a signal in a SIGINFO note.
212 for (const auto &thread_data : m_thread_data) {
213 if (thread_data.signo != 0)
214 siginfo_signal_found = true;
215 if (thread_data.prstatus_sig != 0)
216 prstatus_signal_found = true;
217 }
218 if (!siginfo_signal_found) {
219 // If we don't have signal from SIGINFO use the signal from each threads
220 // PRSTATUS note.
221 if (prstatus_signal_found) {
222 for (auto &thread_data : m_thread_data)
223 thread_data.signo = thread_data.prstatus_sig;
224 } else if (m_thread_data.size() > 0) {
225 // If all else fails force the first thread to be SIGSTOP
226 m_thread_data.begin()->signo =
227 GetUnixSignals()->GetSignalNumberFromName("SIGSTOP");
228 }
229 }
230
231 // Core files are useless without the main executable. See if we can locate
232 // the main executable using data we found in the core file notes.
233 lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
234 if (!exe_module_sp) {
235 // The first entry in the NT_FILE might be our executable
236 if (!m_nt_file_entries.empty()) {
237 ModuleSpec exe_module_spec;
238 exe_module_spec.GetArchitecture() = arch;
239 exe_module_spec.GetFileSpec().SetFile(
240 m_nt_file_entries[0].path.GetCString(), FileSpec::Style::native);
241 if (exe_module_spec.GetFileSpec()) {
242 exe_module_sp = GetTarget().GetOrCreateModule(exe_module_spec,
243 true /* notify */);
244 if (exe_module_sp)
245 GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo);
246 }
247 }
248 }
249 return error;
250}
251
252lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() {
253 if (m_dyld_up.get() == nullptr)
254 m_dyld_up.reset(DynamicLoader::FindPlugin(
255 this, DynamicLoaderPOSIXDYLD::GetPluginNameStatic()));
256 return m_dyld_up.get();
257}
258
259bool ProcessElfCore::DoUpdateThreadList(ThreadList &old_thread_list,
260 ThreadList &new_thread_list) {
261 const uint32_t num_threads = GetNumThreadContexts();
262 if (!m_thread_data_valid)
263 return false;
264
265 for (lldb::tid_t tid = 0; tid < num_threads; ++tid) {
266 const ThreadData &td = m_thread_data[tid];
267 lldb::ThreadSP thread_sp(new ThreadElfCore(*this, td));
268 new_thread_list.AddThread(thread_sp);
269 }
270 return new_thread_list.GetSize(false) > 0;
271}
272
273void ProcessElfCore::RefreshStateAfterStop() {}
274
275Status ProcessElfCore::DoDestroy() { return Status(); }
276
277// Process Queries
278
279bool ProcessElfCore::IsAlive() { return true; }
280
281// Process Memory
282size_t ProcessElfCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
283 Status &error) {
284 // Don't allow the caching that lldb_private::Process::ReadMemory does since
285 // in core files we have it all cached our our core file anyway.
286 return DoReadMemory(addr, buf, size, error);
287}
288
289Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
290 MemoryRegionInfo &region_info) {
291 region_info.Clear();
292 const VMRangeToPermissions::Entry *permission_entry =
293 m_core_range_infos.FindEntryThatContainsOrFollows(load_addr);
294 if (permission_entry) {
295 if (permission_entry->Contains(load_addr)) {
296 region_info.GetRange().SetRangeBase(permission_entry->GetRangeBase());
297 region_info.GetRange().SetRangeEnd(permission_entry->GetRangeEnd());
298 const Flags permissions(permission_entry->data);
299 region_info.SetReadable(permissions.Test(lldb::ePermissionsReadable)
300 ? MemoryRegionInfo::eYes
301 : MemoryRegionInfo::eNo);
302 region_info.SetWritable(permissions.Test(lldb::ePermissionsWritable)
303 ? MemoryRegionInfo::eYes
304 : MemoryRegionInfo::eNo);
305 region_info.SetExecutable(permissions.Test(lldb::ePermissionsExecutable)
306 ? MemoryRegionInfo::eYes
307 : MemoryRegionInfo::eNo);
308 region_info.SetMapped(MemoryRegionInfo::eYes);
309 } else if (load_addr < permission_entry->GetRangeBase()) {
310 region_info.GetRange().SetRangeBase(load_addr);
311 region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase());
312 region_info.SetReadable(MemoryRegionInfo::eNo);
313 region_info.SetWritable(MemoryRegionInfo::eNo);
314 region_info.SetExecutable(MemoryRegionInfo::eNo);
315 region_info.SetMapped(MemoryRegionInfo::eNo);
316 }
317 return Status();
318 }
319
320 region_info.GetRange().SetRangeBase(load_addr);
321 region_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS(18446744073709551615UL));
322 region_info.SetReadable(MemoryRegionInfo::eNo);
323 region_info.SetWritable(MemoryRegionInfo::eNo);
324 region_info.SetExecutable(MemoryRegionInfo::eNo);
325 region_info.SetMapped(MemoryRegionInfo::eNo);
326 return Status();
327}
328
329size_t ProcessElfCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
330 Status &error) {
331 ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
332
333 if (core_objfile == nullptr)
334 return 0;
335
336 // Get the address range
337 const VMRangeToFileOffset::Entry *address_range =
338 m_core_aranges.FindEntryThatContains(addr);
339 if (address_range == nullptr || address_range->GetRangeEnd() < addr) {
340 error.SetErrorStringWithFormat("core file does not contain 0x%" PRIx64"l" "x",
341 addr);
342 return 0;
343 }
344
345 // Convert the address into core file offset
346 const lldb::addr_t offset = addr - address_range->GetRangeBase();
347 const lldb::addr_t file_start = address_range->data.GetRangeBase();
348 const lldb::addr_t file_end = address_range->data.GetRangeEnd();
349 size_t bytes_to_read = size; // Number of bytes to read from the core file
350 size_t bytes_copied = 0; // Number of bytes actually read from the core file
351 lldb::addr_t bytes_left =
352 0; // Number of bytes available in the core file from the given address
353
354 // Don't proceed if core file doesn't contain the actual data for this
355 // address range.
356 if (file_start == file_end)
357 return 0;
358
359 // Figure out how many on-disk bytes remain in this segment starting at the
360 // given offset
361 if (file_end > file_start + offset)
362 bytes_left = file_end - (file_start + offset);
363
364 if (bytes_to_read > bytes_left)
365 bytes_to_read = bytes_left;
366
367 // If there is data available on the core file read it
368 if (bytes_to_read)
369 bytes_copied =
370 core_objfile->CopyData(offset + file_start, bytes_to_read, buf);
371
372 return bytes_copied;
373}
374
375void ProcessElfCore::Clear() {
376 m_thread_list.Clear();
377
378 SetUnixSignals(std::make_shared<UnixSignals>());
379}
380
381void ProcessElfCore::Initialize() {
382 static llvm::once_flag g_once_flag;
383
384 llvm::call_once(g_once_flag, []() {
385 PluginManager::RegisterPlugin(GetPluginNameStatic(),
386 GetPluginDescriptionStatic(), CreateInstance);
387 });
388}
389
390lldb::addr_t ProcessElfCore::GetImageInfoAddress() {
391 ObjectFile *obj_file = GetTarget().GetExecutableModule()->GetObjectFile();
392 Address addr = obj_file->GetImageInfoAddress(&GetTarget());
393
394 if (addr.IsValid())
395 return addr.GetLoadAddress(&GetTarget());
396 return LLDB_INVALID_ADDRESS(18446744073709551615UL);
397}
398
399// Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details.
400static void ParseFreeBSDPrStatus(ThreadData &thread_data,
401 const DataExtractor &data,
402 bool lp64) {
403 lldb::offset_t offset = 0;
404 int pr_version = data.GetU32(&offset);
405
406 Log *log = GetLog(LLDBLog::Process);
407 if (log) {
408 if (pr_version > 1)
409 LLDB_LOGF(log, "FreeBSD PRSTATUS unexpected version %d", pr_version)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("FreeBSD PRSTATUS unexpected version %d"
, pr_version); } while (0)
;
410 }
411
412 // Skip padding, pr_statussz, pr_gregsetsz, pr_fpregsetsz, pr_osreldate
413 if (lp64)
414 offset += 32;
415 else
416 offset += 16;
417
418 thread_data.signo = data.GetU32(&offset); // pr_cursig
419 thread_data.tid = data.GetU32(&offset); // pr_pid
420 if (lp64)
421 offset += 4;
422
423 size_t len = data.GetByteSize() - offset;
424 thread_data.gpregset = DataExtractor(data, offset, len);
425}
426
427// Parse a FreeBSD NT_PRPSINFO note - see FreeBSD sys/procfs.h for details.
428static void ParseFreeBSDPrPsInfo(ProcessElfCore &process,
429 const DataExtractor &data,
430 bool lp64) {
431 lldb::offset_t offset = 0;
432 int pr_version = data.GetU32(&offset);
433
434 Log *log = GetLog(LLDBLog::Process);
435 if (log) {
436 if (pr_version > 1)
437 LLDB_LOGF(log, "FreeBSD PRPSINFO unexpected version %d", pr_version)do { ::lldb_private::Log *log_private = (log); if (log_private
) log_private->Printf("FreeBSD PRPSINFO unexpected version %d"
, pr_version); } while (0)
;
438 }
439
440 // Skip pr_psinfosz, pr_fname, pr_psargs
441 offset += 108;
442 if (lp64)
443 offset += 4;
444
445 process.SetID(data.GetU32(&offset)); // pr_pid
446}
447
448static llvm::Error ParseNetBSDProcInfo(const DataExtractor &data,
449 uint32_t &cpi_nlwps,
450 uint32_t &cpi_signo,
451 uint32_t &cpi_siglwp,
452 uint32_t &cpi_pid) {
453 lldb::offset_t offset = 0;
454
455 uint32_t version = data.GetU32(&offset);
456 if (version != 1)
457 return llvm::make_error<llvm::StringError>(
458 "Error parsing NetBSD core(5) notes: Unsupported procinfo version",
459 llvm::inconvertibleErrorCode());
460
461 uint32_t cpisize = data.GetU32(&offset);
462 if (cpisize != NETBSD::NT_PROCINFO_SIZE)
463 return llvm::make_error<llvm::StringError>(
464 "Error parsing NetBSD core(5) notes: Unsupported procinfo size",
465 llvm::inconvertibleErrorCode());
466
467 cpi_signo = data.GetU32(&offset); /* killing signal */
468
469 offset += NETBSD::NT_PROCINFO_CPI_SIGCODE_SIZE;
470 offset += NETBSD::NT_PROCINFO_CPI_SIGPEND_SIZE;
471 offset += NETBSD::NT_PROCINFO_CPI_SIGMASK_SIZE;
472 offset += NETBSD::NT_PROCINFO_CPI_SIGIGNORE_SIZE;
473 offset += NETBSD::NT_PROCINFO_CPI_SIGCATCH_SIZE;
474 cpi_pid = data.GetU32(&offset);
475 offset += NETBSD::NT_PROCINFO_CPI_PPID_SIZE;
476 offset += NETBSD::NT_PROCINFO_CPI_PGRP_SIZE;
477 offset += NETBSD::NT_PROCINFO_CPI_SID_SIZE;
478 offset += NETBSD::NT_PROCINFO_CPI_RUID_SIZE;
479 offset += NETBSD::NT_PROCINFO_CPI_EUID_SIZE;
480 offset += NETBSD::NT_PROCINFO_CPI_SVUID_SIZE;
481 offset += NETBSD::NT_PROCINFO_CPI_RGID_SIZE;
482 offset += NETBSD::NT_PROCINFO_CPI_EGID_SIZE;
483 offset += NETBSD::NT_PROCINFO_CPI_SVGID_SIZE;
484 cpi_nlwps = data.GetU32(&offset); /* number of LWPs */
485
486 offset += NETBSD::NT_PROCINFO_CPI_NAME_SIZE;
487 cpi_siglwp = data.GetU32(&offset); /* LWP target of killing signal */
488
489 return llvm::Error::success();
490}
491
492static void ParseOpenBSDProcInfo(ThreadData &thread_data,
493 const DataExtractor &data) {
494 lldb::offset_t offset = 0;
495
496 int version = data.GetU32(&offset);
497 if (version != 1)
498 return;
499
500 offset += 4;
501 thread_data.signo = data.GetU32(&offset);
502}
503
504llvm::Expected<std::vector<CoreNote>>
505ProcessElfCore::parseSegment(const DataExtractor &segment) {
506 lldb::offset_t offset = 0;
507 std::vector<CoreNote> result;
508
509 while (offset < segment.GetByteSize()) {
510 ELFNote note = ELFNote();
511 if (!note.Parse(segment, &offset))
512 return llvm::make_error<llvm::StringError>(
513 "Unable to parse note segment", llvm::inconvertibleErrorCode());
514
515 size_t note_start = offset;
516 size_t note_size = llvm::alignTo(note.n_descsz, 4);
517
518 result.push_back({note, DataExtractor(segment, note_start, note_size)});
519 offset += note_size;
520 }
521
522 return std::move(result);
523}
524
525llvm::Error ProcessElfCore::parseFreeBSDNotes(llvm::ArrayRef<CoreNote> notes) {
526 ArchSpec arch = GetArchitecture();
527 bool lp64 = (arch.GetMachine() == llvm::Triple::aarch64 ||
528 arch.GetMachine() == llvm::Triple::mips64 ||
529 arch.GetMachine() == llvm::Triple::ppc64 ||
530 arch.GetMachine() == llvm::Triple::x86_64);
531 bool have_prstatus = false;
532 bool have_prpsinfo = false;
533 ThreadData thread_data;
534 for (const auto &note : notes) {
535 if (note.info.n_name != "FreeBSD")
536 continue;
537
538 if ((note.info.n_type == ELF::NT_PRSTATUS && have_prstatus) ||
539 (note.info.n_type == ELF::NT_PRPSINFO && have_prpsinfo)) {
540 assert(thread_data.gpregset.GetByteSize() > 0)(static_cast <bool> (thread_data.gpregset.GetByteSize()
> 0) ? void (0) : __assert_fail ("thread_data.gpregset.GetByteSize() > 0"
, "lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp", 540
, __extension__ __PRETTY_FUNCTION__))
;
541 // Add the new thread to thread list
542 m_thread_data.push_back(thread_data);
543 thread_data = ThreadData();
544 have_prstatus = false;
545 have_prpsinfo = false;
546 }
547
548 switch (note.info.n_type) {
549 case ELF::NT_PRSTATUS:
550 have_prstatus = true;
551 ParseFreeBSDPrStatus(thread_data, note.data, lp64);
552 break;
553 case ELF::NT_PRPSINFO:
554 have_prpsinfo = true;
555 ParseFreeBSDPrPsInfo(*this, note.data, lp64);
556 break;
557 case ELF::NT_FREEBSD_THRMISC: {
558 lldb::offset_t offset = 0;
559 thread_data.name = note.data.GetCStr(&offset, 20);
560 break;
561 }
562 case ELF::NT_FREEBSD_PROCSTAT_AUXV:
563 // FIXME: FreeBSD sticks an int at the beginning of the note
564 m_auxv = DataExtractor(note.data, 4, note.data.GetByteSize() - 4);
565 break;
566 default:
567 thread_data.notes.push_back(note);
568 break;
569 }
570 }
571 if (!have_prstatus) {
572 return llvm::make_error<llvm::StringError>(
573 "Could not find NT_PRSTATUS note in core file.",
574 llvm::inconvertibleErrorCode());
575 }
576 m_thread_data.push_back(thread_data);
577 return llvm::Error::success();
578}
579
580/// NetBSD specific Thread context from PT_NOTE segment
581///
582/// NetBSD ELF core files use notes to provide information about
583/// the process's state. The note name is "NetBSD-CORE" for
584/// information that is global to the process, and "NetBSD-CORE@nn",
585/// where "nn" is the lwpid of the LWP that the information belongs
586/// to (such as register state).
587///
588/// NetBSD uses the following note identifiers:
589///
590/// ELF_NOTE_NETBSD_CORE_PROCINFO (value 1)
591/// Note is a "netbsd_elfcore_procinfo" structure.
592/// ELF_NOTE_NETBSD_CORE_AUXV (value 2; since NetBSD 8.0)
593/// Note is an array of AuxInfo structures.
594///
595/// NetBSD also uses ptrace(2) request numbers (the ones that exist in
596/// machine-dependent space) to identify register info notes. The
597/// info in such notes is in the same format that ptrace(2) would
598/// export that information.
599///
600/// For more information see /usr/include/sys/exec_elf.h
601///
602llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) {
603 ThreadData thread_data;
604 bool had_nt_regs = false;
605
606 // To be extracted from struct netbsd_elfcore_procinfo
607 // Used to sanity check of the LWPs of the process
608 uint32_t nlwps = 0;
609 uint32_t signo; // killing signal
610 uint32_t siglwp; // LWP target of killing signal
611 uint32_t pr_pid;
612
613 for (const auto &note : notes) {
614 llvm::StringRef name = note.info.n_name;
615
616 if (name == "NetBSD-CORE") {
617 if (note.info.n_type == NETBSD::NT_PROCINFO) {
618 llvm::Error error = ParseNetBSDProcInfo(note.data, nlwps, signo,
619 siglwp, pr_pid);
620 if (error)
621 return error;
622 SetID(pr_pid);
623 } else if (note.info.n_type == NETBSD::NT_AUXV) {
624 m_auxv = note.data;
625 }
626 } else if (name.consume_front("NetBSD-CORE@")) {
627 lldb::tid_t tid;
628 if (name.getAsInteger(10, tid))
629 return llvm::make_error<llvm::StringError>(
630 "Error parsing NetBSD core(5) notes: Cannot convert LWP ID "
631 "to integer",
632 llvm::inconvertibleErrorCode());
633
634 switch (GetArchitecture().GetMachine()) {
635 case llvm::Triple::aarch64: {
636 // Assume order PT_GETREGS, PT_GETFPREGS
637 if (note.info.n_type == NETBSD::AARCH64::NT_REGS) {
638 // If this is the next thread, push the previous one first.
639 if (had_nt_regs) {
640 m_thread_data.push_back(thread_data);
641 thread_data = ThreadData();
642 had_nt_regs = false;
643 }
644
645 thread_data.gpregset = note.data;
646 thread_data.tid = tid;
647 if (thread_data.gpregset.GetByteSize() == 0)
648 return llvm::make_error<llvm::StringError>(
649 "Could not find general purpose registers note in core file.",
650 llvm::inconvertibleErrorCode());
651 had_nt_regs = true;
652 } else if (note.info.n_type == NETBSD::AARCH64::NT_FPREGS) {
653 if (!had_nt_regs || tid != thread_data.tid)
654 return llvm::make_error<llvm::StringError>(
655 "Error parsing NetBSD core(5) notes: Unexpected order "
656 "of NOTEs PT_GETFPREG before PT_GETREG",
657 llvm::inconvertibleErrorCode());
658 thread_data.notes.push_back(note);
659 }
660 } break;
661 case llvm::Triple::x86: {
662 // Assume order PT_GETREGS, PT_GETFPREGS
663 if (note.info.n_type == NETBSD::I386::NT_REGS) {
664 // If this is the next thread, push the previous one first.
665 if (had_nt_regs) {
666 m_thread_data.push_back(thread_data);
667 thread_data = ThreadData();
668 had_nt_regs = false;
Value stored to 'had_nt_regs' is never read
669 }
670
671 thread_data.gpregset = note.data;
672 thread_data.tid = tid;
673 if (thread_data.gpregset.GetByteSize() == 0)
674 return llvm::make_error<llvm::StringError>(
675 "Could not find general purpose registers note in core file.",
676 llvm::inconvertibleErrorCode());
677 had_nt_regs = true;
678 } else if (note.info.n_type == NETBSD::I386::NT_FPREGS) {
679 if (!had_nt_regs || tid != thread_data.tid)
680 return llvm::make_error<llvm::StringError>(
681 "Error parsing NetBSD core(5) notes: Unexpected order "
682 "of NOTEs PT_GETFPREG before PT_GETREG",
683 llvm::inconvertibleErrorCode());
684 thread_data.notes.push_back(note);
685 }
686 } break;
687 case llvm::Triple::x86_64: {
688 // Assume order PT_GETREGS, PT_GETFPREGS
689 if (note.info.n_type == NETBSD::AMD64::NT_REGS) {
690 // If this is the next thread, push the previous one first.
691 if (had_nt_regs) {
692 m_thread_data.push_back(thread_data);
693 thread_data = ThreadData();
694 had_nt_regs = false;
695 }
696
697 thread_data.gpregset = note.data;
698 thread_data.tid = tid;
699 if (thread_data.gpregset.GetByteSize() == 0)
700 return llvm::make_error<llvm::StringError>(
701 "Could not find general purpose registers note in core file.",
702 llvm::inconvertibleErrorCode());
703 had_nt_regs = true;
704 } else if (note.info.n_type == NETBSD::AMD64::NT_FPREGS) {
705 if (!had_nt_regs || tid != thread_data.tid)
706 return llvm::make_error<llvm::StringError>(
707 "Error parsing NetBSD core(5) notes: Unexpected order "
708 "of NOTEs PT_GETFPREG before PT_GETREG",
709 llvm::inconvertibleErrorCode());
710 thread_data.notes.push_back(note);
711 }
712 } break;
713 default:
714 break;
715 }
716 }
717 }
718
719 // Push the last thread.
720 if (had_nt_regs)
721 m_thread_data.push_back(thread_data);
722
723 if (m_thread_data.empty())
724 return llvm::make_error<llvm::StringError>(
725 "Error parsing NetBSD core(5) notes: No threads information "
726 "specified in notes",
727 llvm::inconvertibleErrorCode());
728
729 if (m_thread_data.size() != nlwps)
730 return llvm::make_error<llvm::StringError>(
731 "Error parsing NetBSD core(5) notes: Mismatch between the number "
732 "of LWPs in netbsd_elfcore_procinfo and the number of LWPs specified "
733 "by MD notes",
734 llvm::inconvertibleErrorCode());
735
736 // Signal targeted at the whole process.
737 if (siglwp == 0) {
738 for (auto &data : m_thread_data)
739 data.signo = signo;
740 }
741 // Signal destined for a particular LWP.
742 else {
743 bool passed = false;
744
745 for (auto &data : m_thread_data) {
746 if (data.tid == siglwp) {
747 data.signo = signo;
748 passed = true;
749 break;
750 }
751 }
752
753 if (!passed)
754 return llvm::make_error<llvm::StringError>(
755 "Error parsing NetBSD core(5) notes: Signal passed to unknown LWP",
756 llvm::inconvertibleErrorCode());
757 }
758
759 return llvm::Error::success();
760}
761
762llvm::Error ProcessElfCore::parseOpenBSDNotes(llvm::ArrayRef<CoreNote> notes) {
763 ThreadData thread_data;
764 for (const auto &note : notes) {
765 // OpenBSD per-thread information is stored in notes named "OpenBSD@nnn" so
766 // match on the initial part of the string.
767 if (!llvm::StringRef(note.info.n_name).startswith("OpenBSD"))
768 continue;
769
770 switch (note.info.n_type) {
771 case OPENBSD::NT_PROCINFO:
772 ParseOpenBSDProcInfo(thread_data, note.data);
773 break;
774 case OPENBSD::NT_AUXV:
775 m_auxv = note.data;
776 break;
777 case OPENBSD::NT_REGS:
778 thread_data.gpregset = note.data;
779 break;
780 default:
781 thread_data.notes.push_back(note);
782 break;
783 }
784 }
785 if (thread_data.gpregset.GetByteSize() == 0) {
786 return llvm::make_error<llvm::StringError>(
787 "Could not find general purpose registers note in core file.",
788 llvm::inconvertibleErrorCode());
789 }
790 m_thread_data.push_back(thread_data);
791 return llvm::Error::success();
792}
793
794/// A description of a linux process usually contains the following NOTE
795/// entries:
796/// - NT_PRPSINFO - General process information like pid, uid, name, ...
797/// - NT_SIGINFO - Information about the signal that terminated the process
798/// - NT_AUXV - Process auxiliary vector
799/// - NT_FILE - Files mapped into memory
800///
801/// Additionally, for each thread in the process the core file will contain at
802/// least the NT_PRSTATUS note, containing the thread id and general purpose
803/// registers. It may include additional notes for other register sets (floating
804/// point and vector registers, ...). The tricky part here is that some of these
805/// notes have "CORE" in their owner fields, while other set it to "LINUX".
806llvm::Error ProcessElfCore::parseLinuxNotes(llvm::ArrayRef<CoreNote> notes) {
807 const ArchSpec &arch = GetArchitecture();
808 bool have_prstatus = false;
809 bool have_prpsinfo = false;
810 ThreadData thread_data;
811 for (const auto &note : notes) {
812 if (note.info.n_name != "CORE" && note.info.n_name != "LINUX")
813 continue;
814
815 if ((note.info.n_type == ELF::NT_PRSTATUS && have_prstatus) ||
816 (note.info.n_type == ELF::NT_PRPSINFO && have_prpsinfo)) {
817 assert(thread_data.gpregset.GetByteSize() > 0)(static_cast <bool> (thread_data.gpregset.GetByteSize()
> 0) ? void (0) : __assert_fail ("thread_data.gpregset.GetByteSize() > 0"
, "lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp", 817
, __extension__ __PRETTY_FUNCTION__))
;
818 // Add the new thread to thread list
819 m_thread_data.push_back(thread_data);
820 thread_data = ThreadData();
821 have_prstatus = false;
822 have_prpsinfo = false;
823 }
824
825 switch (note.info.n_type) {
826 case ELF::NT_PRSTATUS: {
827 have_prstatus = true;
828 ELFLinuxPrStatus prstatus;
829 Status status = prstatus.Parse(note.data, arch);
830 if (status.Fail())
831 return status.ToError();
832 thread_data.prstatus_sig = prstatus.pr_cursig;
833 thread_data.tid = prstatus.pr_pid;
834 uint32_t header_size = ELFLinuxPrStatus::GetSize(arch);
835 size_t len = note.data.GetByteSize() - header_size;
836 thread_data.gpregset = DataExtractor(note.data, header_size, len);
837 break;
838 }
839 case ELF::NT_PRPSINFO: {
840 have_prpsinfo = true;
841 ELFLinuxPrPsInfo prpsinfo;
842 Status status = prpsinfo.Parse(note.data, arch);
843 if (status.Fail())
844 return status.ToError();
845 thread_data.name.assign (prpsinfo.pr_fname, strnlen (prpsinfo.pr_fname, sizeof (prpsinfo.pr_fname)));
846 SetID(prpsinfo.pr_pid);
847 break;
848 }
849 case ELF::NT_SIGINFO: {
850 ELFLinuxSigInfo siginfo;
851 Status status = siginfo.Parse(note.data, arch);
852 if (status.Fail())
853 return status.ToError();
854 thread_data.signo = siginfo.si_signo;
855 break;
856 }
857 case ELF::NT_FILE: {
858 m_nt_file_entries.clear();
859 lldb::offset_t offset = 0;
860 const uint64_t count = note.data.GetAddress(&offset);
861 note.data.GetAddress(&offset); // Skip page size
862 for (uint64_t i = 0; i < count; ++i) {
863 NT_FILE_Entry entry;
864 entry.start = note.data.GetAddress(&offset);
865 entry.end = note.data.GetAddress(&offset);
866 entry.file_ofs = note.data.GetAddress(&offset);
867 m_nt_file_entries.push_back(entry);
868 }
869 for (uint64_t i = 0; i < count; ++i) {
870 const char *path = note.data.GetCStr(&offset);
871 if (path && path[0])
872 m_nt_file_entries[i].path.SetCString(path);
873 }
874 break;
875 }
876 case ELF::NT_AUXV:
877 m_auxv = note.data;
878 break;
879 default:
880 thread_data.notes.push_back(note);
881 break;
882 }
883 }
884 // Add last entry in the note section
885 if (have_prstatus)
886 m_thread_data.push_back(thread_data);
887 return llvm::Error::success();
888}
889
890/// Parse Thread context from PT_NOTE segment and store it in the thread list
891/// A note segment consists of one or more NOTE entries, but their types and
892/// meaning differ depending on the OS.
893llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment(
894 const elf::ELFProgramHeader &segment_header,
895 const DataExtractor &segment_data) {
896 assert(segment_header.p_type == llvm::ELF::PT_NOTE)(static_cast <bool> (segment_header.p_type == llvm::ELF
::PT_NOTE) ? void (0) : __assert_fail ("segment_header.p_type == llvm::ELF::PT_NOTE"
, "lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp", 896
, __extension__ __PRETTY_FUNCTION__))
;
897
898 auto notes_or_error = parseSegment(segment_data);
899 if(!notes_or_error)
900 return notes_or_error.takeError();
901 switch (GetArchitecture().GetTriple().getOS()) {
902 case llvm::Triple::FreeBSD:
903 return parseFreeBSDNotes(*notes_or_error);
904 case llvm::Triple::Linux:
905 return parseLinuxNotes(*notes_or_error);
906 case llvm::Triple::NetBSD:
907 return parseNetBSDNotes(*notes_or_error);
908 case llvm::Triple::OpenBSD:
909 return parseOpenBSDNotes(*notes_or_error);
910 default:
911 return llvm::make_error<llvm::StringError>(
912 "Don't know how to parse core file. Unsupported OS.",
913 llvm::inconvertibleErrorCode());
914 }
915}
916
917uint32_t ProcessElfCore::GetNumThreadContexts() {
918 if (!m_thread_data_valid)
919 DoLoadCore();
920 return m_thread_data.size();
921}
922
923ArchSpec ProcessElfCore::GetArchitecture() {
924 ArchSpec arch = m_core_module_sp->GetObjectFile()->GetArchitecture();
925
926 ArchSpec target_arch = GetTarget().GetArchitecture();
927 arch.MergeFrom(target_arch);
928
929 // On MIPS there is no way to differentiate betwenn 32bit and 64bit core
930 // files and this information can't be merged in from the target arch so we
931 // fail back to unconditionally returning the target arch in this config.
932 if (target_arch.IsMIPS()) {
933 return target_arch;
934 }
935
936 return arch;
937}
938
939DataExtractor ProcessElfCore::GetAuxvData() {
940 const uint8_t *start = m_auxv.GetDataStart();
941 size_t len = m_auxv.GetByteSize();
942 lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(start, len));
943 return DataExtractor(buffer, GetByteOrder(), GetAddressByteSize());
944}
945
946bool ProcessElfCore::GetProcessInfo(ProcessInstanceInfo &info) {
947 info.Clear();
948 info.SetProcessID(GetID());
949 info.SetArchitecture(GetArchitecture());
950 lldb::ModuleSP module_sp = GetTarget().GetExecutableModule();
951 if (module_sp) {
952 const bool add_exe_file_as_first_arg = false;
953 info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(),
954 add_exe_file_as_first_arg);
955 }
956 return true;
957}