1 //===-- MinidumpFileBuilder.cpp -------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "MinidumpFileBuilder.h"
11 #include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/ModuleList.h"
15 #include "lldb/Core/Section.h"
16 #include "lldb/Target/MemoryRegionInfo.h"
17 #include "lldb/Target/Process.h"
18 #include "lldb/Target/RegisterContext.h"
19 #include "lldb/Target/StopInfo.h"
20 #include "lldb/Target/ThreadList.h"
21 #include "lldb/Utility/DataExtractor.h"
22 #include "lldb/Utility/RegisterValue.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/BinaryFormat/Minidump.h"
26 #include "llvm/Support/ConvertUTF.h"
27 #include "llvm/Support/Error.h"
29 #include "Plugins/Process/minidump/MinidumpTypes.h"
34 using namespace lldb_private
;
35 using namespace llvm::minidump
;
37 void MinidumpFileBuilder::AddDirectory(StreamType type
, size_t stream_size
) {
38 LocationDescriptor loc
;
39 loc
.DataSize
= static_cast<llvm::support::ulittle32_t
>(stream_size
);
40 // Stream will begin at the current end of data section
41 loc
.RVA
= static_cast<llvm::support::ulittle32_t
>(GetCurrentDataEndOffset());
44 dir
.Type
= static_cast<llvm::support::little_t
<StreamType
>>(type
);
47 m_directories
.push_back(dir
);
50 Status
MinidumpFileBuilder::AddSystemInfo(const llvm::Triple
&target_triple
) {
52 AddDirectory(StreamType::SystemInfo
, sizeof(llvm::minidump::SystemInfo
));
54 llvm::minidump::ProcessorArchitecture arch
;
55 switch (target_triple
.getArch()) {
56 case llvm::Triple::ArchType::x86_64
:
57 arch
= ProcessorArchitecture::AMD64
;
59 case llvm::Triple::ArchType::x86
:
60 arch
= ProcessorArchitecture::X86
;
62 case llvm::Triple::ArchType::arm
:
63 arch
= ProcessorArchitecture::ARM
;
65 case llvm::Triple::ArchType::aarch64
:
66 arch
= ProcessorArchitecture::ARM64
;
68 case llvm::Triple::ArchType::mips64
:
69 case llvm::Triple::ArchType::mips64el
:
70 case llvm::Triple::ArchType::mips
:
71 case llvm::Triple::ArchType::mipsel
:
72 arch
= ProcessorArchitecture::MIPS
;
74 case llvm::Triple::ArchType::ppc64
:
75 case llvm::Triple::ArchType::ppc
:
76 case llvm::Triple::ArchType::ppc64le
:
77 arch
= ProcessorArchitecture::PPC
;
80 error
.SetErrorStringWithFormat("Architecture %s not supported.",
81 target_triple
.getArchName().str().c_str());
85 llvm::support::little_t
<OSPlatform
> platform_id
;
86 switch (target_triple
.getOS()) {
87 case llvm::Triple::OSType::Linux
:
88 if (target_triple
.getEnvironment() ==
89 llvm::Triple::EnvironmentType::Android
)
90 platform_id
= OSPlatform::Android
;
92 platform_id
= OSPlatform::Linux
;
94 case llvm::Triple::OSType::Win32
:
95 platform_id
= OSPlatform::Win32NT
;
97 case llvm::Triple::OSType::MacOSX
:
98 platform_id
= OSPlatform::MacOSX
;
100 case llvm::Triple::OSType::IOS
:
101 platform_id
= OSPlatform::IOS
;
104 error
.SetErrorStringWithFormat("OS %s not supported.",
105 target_triple
.getOSName().str().c_str());
109 llvm::minidump::SystemInfo sys_info
;
110 sys_info
.ProcessorArch
=
111 static_cast<llvm::support::little_t
<ProcessorArchitecture
>>(arch
);
112 // Global offset to beginning of a csd_string in a data section
113 sys_info
.CSDVersionRVA
= static_cast<llvm::support::ulittle32_t
>(
114 GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo
));
115 sys_info
.PlatformId
= platform_id
;
116 m_data
.AppendData(&sys_info
, sizeof(llvm::minidump::SystemInfo
));
118 std::string csd_string
;
120 error
= WriteString(csd_string
, &m_data
);
122 error
.SetErrorString("Unable to convert the csd string to UTF16.");
129 Status
WriteString(const std::string
&to_write
,
130 lldb_private::DataBufferHeap
*buffer
) {
132 // let the StringRef eat also null termination char
133 llvm::StringRef
to_write_ref(to_write
.c_str(), to_write
.size() + 1);
134 llvm::SmallVector
<llvm::UTF16
, 128> to_write_utf16
;
136 bool converted
= convertUTF8ToUTF16String(to_write_ref
, to_write_utf16
);
138 error
.SetErrorStringWithFormat(
139 "Unable to convert the string to UTF16. Failed to convert %s",
144 // size of the UTF16 string should be written without the null termination
145 // character that is stored in 2 bytes
146 llvm::support::ulittle32_t
to_write_size(to_write_utf16
.size_in_bytes() - 2);
148 buffer
->AppendData(&to_write_size
, sizeof(llvm::support::ulittle32_t
));
149 buffer
->AppendData(to_write_utf16
.data(), to_write_utf16
.size_in_bytes());
154 llvm::Expected
<uint64_t> getModuleFileSize(Target
&target
,
155 const ModuleSP
&mod
) {
156 SectionSP sect_sp
= mod
->GetObjectFile()->GetBaseAddress().GetSection();
157 uint64_t SizeOfImage
= 0;
160 return llvm::createStringError(std::errc::operation_not_supported
,
161 "Couldn't obtain the section information.");
163 lldb::addr_t sect_addr
= sect_sp
->GetLoadBaseAddress(&target
);
164 // Use memory size since zero fill sections, like ".bss", will be smaller on
166 lldb::addr_t sect_size
= sect_sp
->GetByteSize();
167 // This will usually be zero, but make sure to calculate the BaseOfImage
169 const lldb::addr_t base_sect_offset
=
170 mod
->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target
) -
172 SizeOfImage
= sect_size
- base_sect_offset
;
173 lldb::addr_t next_sect_addr
= sect_addr
+ sect_size
;
174 Address sect_so_addr
;
175 target
.ResolveLoadAddress(next_sect_addr
, sect_so_addr
);
176 lldb::SectionSP next_sect_sp
= sect_so_addr
.GetSection();
177 while (next_sect_sp
&&
178 next_sect_sp
->GetLoadBaseAddress(&target
) == next_sect_addr
) {
179 sect_size
= sect_sp
->GetByteSize();
180 SizeOfImage
+= sect_size
;
181 next_sect_addr
+= sect_size
;
182 target
.ResolveLoadAddress(next_sect_addr
, sect_so_addr
);
183 next_sect_sp
= sect_so_addr
.GetSection();
189 // ModuleList stream consists of a number of modules, followed by an array
190 // of llvm::minidump::Module's structures. Every structure informs about a
191 // single module. Additional data of variable length, such as module's names,
192 // are stored just after the ModuleList stream. The llvm::minidump::Module
193 // structures point to this helper data by global offset.
194 Status
MinidumpFileBuilder::AddModuleList(Target
&target
) {
195 constexpr size_t minidump_module_size
= sizeof(llvm::minidump::Module
);
198 const ModuleList
&modules
= target
.GetImages();
199 llvm::support::ulittle32_t modules_count
=
200 static_cast<llvm::support::ulittle32_t
>(modules
.GetSize());
202 // This helps us with getting the correct global offset in minidump
203 // file later, when we will be setting up offsets from the
204 // the llvm::minidump::Module's structures into helper data
205 size_t size_before
= GetCurrentDataEndOffset();
207 // This is the size of the main part of the ModuleList stream.
208 // It consists of a module number and corresponding number of
209 // structs describing individual modules
210 size_t module_stream_size
=
211 sizeof(llvm::support::ulittle32_t
) + modules_count
* minidump_module_size
;
213 // Adding directory describing this stream.
214 AddDirectory(StreamType::ModuleList
, module_stream_size
);
216 m_data
.AppendData(&modules_count
, sizeof(llvm::support::ulittle32_t
));
218 // Temporary storage for the helper data (of variable length)
219 // as these cannot be dumped to m_data before dumping entire
220 // array of module structures.
221 DataBufferHeap helper_data
;
223 for (size_t i
= 0; i
< modules_count
; ++i
) {
224 ModuleSP mod
= modules
.GetModuleAtIndex(i
);
225 std::string module_name
= mod
->GetSpecificationDescription();
226 auto maybe_mod_size
= getModuleFileSize(target
, mod
);
227 if (!maybe_mod_size
) {
228 error
.SetErrorStringWithFormat("Unable to get the size of module %s.",
229 module_name
.c_str());
233 uint64_t mod_size
= std::move(*maybe_mod_size
);
235 llvm::support::ulittle32_t signature
=
236 static_cast<llvm::support::ulittle32_t
>(
237 static_cast<uint32_t>(minidump::CvSignature::ElfBuildId
));
238 auto uuid
= mod
->GetUUID().GetBytes();
240 VSFixedFileInfo info
;
241 info
.Signature
= static_cast<llvm::support::ulittle32_t
>(0u);
242 info
.StructVersion
= static_cast<llvm::support::ulittle32_t
>(0u);
243 info
.FileVersionHigh
= static_cast<llvm::support::ulittle32_t
>(0u);
244 info
.FileVersionLow
= static_cast<llvm::support::ulittle32_t
>(0u);
245 info
.ProductVersionHigh
= static_cast<llvm::support::ulittle32_t
>(0u);
246 info
.ProductVersionLow
= static_cast<llvm::support::ulittle32_t
>(0u);
247 info
.FileFlagsMask
= static_cast<llvm::support::ulittle32_t
>(0u);
248 info
.FileFlags
= static_cast<llvm::support::ulittle32_t
>(0u);
249 info
.FileOS
= static_cast<llvm::support::ulittle32_t
>(0u);
250 info
.FileType
= static_cast<llvm::support::ulittle32_t
>(0u);
251 info
.FileSubtype
= static_cast<llvm::support::ulittle32_t
>(0u);
252 info
.FileDateHigh
= static_cast<llvm::support::ulittle32_t
>(0u);
253 info
.FileDateLow
= static_cast<llvm::support::ulittle32_t
>(0u);
255 LocationDescriptor ld
;
256 ld
.DataSize
= static_cast<llvm::support::ulittle32_t
>(0u);
257 ld
.RVA
= static_cast<llvm::support::ulittle32_t
>(0u);
259 // Setting up LocationDescriptor for uuid string. The global offset into
260 // minidump file is calculated.
261 LocationDescriptor ld_cv
;
262 ld_cv
.DataSize
= static_cast<llvm::support::ulittle32_t
>(
263 sizeof(llvm::support::ulittle32_t
) + uuid
.size());
264 ld_cv
.RVA
= static_cast<llvm::support::ulittle32_t
>(
265 size_before
+ module_stream_size
+ helper_data
.GetByteSize());
267 helper_data
.AppendData(&signature
, sizeof(llvm::support::ulittle32_t
));
268 helper_data
.AppendData(uuid
.begin(), uuid
.size());
270 llvm::minidump::Module m
;
271 m
.BaseOfImage
= static_cast<llvm::support::ulittle64_t
>(
272 mod
->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target
));
273 m
.SizeOfImage
= static_cast<llvm::support::ulittle32_t
>(mod_size
);
274 m
.Checksum
= static_cast<llvm::support::ulittle32_t
>(0);
276 static_cast<llvm::support::ulittle32_t
>(std::time(nullptr));
277 m
.ModuleNameRVA
= static_cast<llvm::support::ulittle32_t
>(
278 size_before
+ module_stream_size
+ helper_data
.GetByteSize());
279 m
.VersionInfo
= info
;
283 error
= WriteString(module_name
, &helper_data
);
288 m_data
.AppendData(&m
, sizeof(llvm::minidump::Module
));
291 m_data
.AppendData(helper_data
.GetBytes(), helper_data
.GetByteSize());
295 uint16_t read_register_u16_raw(RegisterContext
*reg_ctx
,
296 const std::string
®_name
) {
297 const RegisterInfo
*reg_info
= reg_ctx
->GetRegisterInfoByName(reg_name
);
300 lldb_private::RegisterValue reg_value
;
301 bool success
= reg_ctx
->ReadRegister(reg_info
, reg_value
);
304 return reg_value
.GetAsUInt16();
307 uint32_t read_register_u32_raw(RegisterContext
*reg_ctx
,
308 const std::string
®_name
) {
309 const RegisterInfo
*reg_info
= reg_ctx
->GetRegisterInfoByName(reg_name
);
312 lldb_private::RegisterValue reg_value
;
313 bool success
= reg_ctx
->ReadRegister(reg_info
, reg_value
);
316 return reg_value
.GetAsUInt32();
319 uint64_t read_register_u64_raw(RegisterContext
*reg_ctx
,
320 const std::string
®_name
) {
321 const RegisterInfo
*reg_info
= reg_ctx
->GetRegisterInfoByName(reg_name
);
324 lldb_private::RegisterValue reg_value
;
325 bool success
= reg_ctx
->ReadRegister(reg_info
, reg_value
);
328 return reg_value
.GetAsUInt64();
331 llvm::support::ulittle16_t
read_register_u16(RegisterContext
*reg_ctx
,
332 const std::string
®_name
) {
333 return static_cast<llvm::support::ulittle16_t
>(
334 read_register_u16_raw(reg_ctx
, reg_name
));
337 llvm::support::ulittle32_t
read_register_u32(RegisterContext
*reg_ctx
,
338 const std::string
®_name
) {
339 return static_cast<llvm::support::ulittle32_t
>(
340 read_register_u32_raw(reg_ctx
, reg_name
));
343 llvm::support::ulittle64_t
read_register_u64(RegisterContext
*reg_ctx
,
344 const std::string
®_name
) {
345 return static_cast<llvm::support::ulittle64_t
>(
346 read_register_u64_raw(reg_ctx
, reg_name
));
349 lldb_private::minidump::MinidumpContext_x86_64
350 GetThreadContext_64(RegisterContext
*reg_ctx
) {
351 lldb_private::minidump::MinidumpContext_x86_64 thread_context
= {};
352 thread_context
.p1_home
= {};
353 thread_context
.context_flags
= static_cast<uint32_t>(
354 lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag
|
355 lldb_private::minidump::MinidumpContext_x86_64_Flags::Control
|
356 lldb_private::minidump::MinidumpContext_x86_64_Flags::Segments
|
357 lldb_private::minidump::MinidumpContext_x86_64_Flags::Integer
);
358 thread_context
.rax
= read_register_u64(reg_ctx
, "rax");
359 thread_context
.rbx
= read_register_u64(reg_ctx
, "rbx");
360 thread_context
.rcx
= read_register_u64(reg_ctx
, "rcx");
361 thread_context
.rdx
= read_register_u64(reg_ctx
, "rdx");
362 thread_context
.rdi
= read_register_u64(reg_ctx
, "rdi");
363 thread_context
.rsi
= read_register_u64(reg_ctx
, "rsi");
364 thread_context
.rbp
= read_register_u64(reg_ctx
, "rbp");
365 thread_context
.rsp
= read_register_u64(reg_ctx
, "rsp");
366 thread_context
.r8
= read_register_u64(reg_ctx
, "r8");
367 thread_context
.r9
= read_register_u64(reg_ctx
, "r9");
368 thread_context
.r10
= read_register_u64(reg_ctx
, "r10");
369 thread_context
.r11
= read_register_u64(reg_ctx
, "r11");
370 thread_context
.r12
= read_register_u64(reg_ctx
, "r12");
371 thread_context
.r13
= read_register_u64(reg_ctx
, "r13");
372 thread_context
.r14
= read_register_u64(reg_ctx
, "r14");
373 thread_context
.r15
= read_register_u64(reg_ctx
, "r15");
374 thread_context
.rip
= read_register_u64(reg_ctx
, "rip");
375 thread_context
.eflags
= read_register_u32(reg_ctx
, "rflags");
376 thread_context
.cs
= read_register_u16(reg_ctx
, "cs");
377 thread_context
.fs
= read_register_u16(reg_ctx
, "fs");
378 thread_context
.gs
= read_register_u16(reg_ctx
, "gs");
379 thread_context
.ss
= read_register_u16(reg_ctx
, "ss");
380 thread_context
.ds
= read_register_u16(reg_ctx
, "ds");
381 return thread_context
;
384 // Function returns start and size of the memory region that contains
385 // memory location pointed to by the current stack pointer.
386 llvm::Expected
<std::pair
<addr_t
, addr_t
>>
387 findStackHelper(const lldb::ProcessSP
&process_sp
, uint64_t rsp
) {
388 MemoryRegionInfo range_info
;
389 Status error
= process_sp
->GetMemoryRegionInfo(rsp
, range_info
);
390 // Skip failed memory region requests or any regions with no permissions.
391 if (error
.Fail() || range_info
.GetLLDBPermissions() == 0)
392 return llvm::createStringError(
393 std::errc::not_supported
,
394 "unable to load stack segment of the process");
396 const addr_t addr
= range_info
.GetRange().GetRangeBase();
397 const addr_t size
= range_info
.GetRange().GetByteSize();
400 return llvm::createStringError(std::errc::not_supported
,
401 "stack segment of the process is empty");
403 return std::make_pair(addr
, size
);
406 Status
MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP
&process_sp
) {
407 constexpr size_t minidump_thread_size
= sizeof(llvm::minidump::Thread
);
408 lldb_private::ThreadList thread_list
= process_sp
->GetThreadList();
410 // size of the entire thread stream consists of:
411 // number of threads and threads array
412 size_t thread_stream_size
= sizeof(llvm::support::ulittle32_t
) +
413 thread_list
.GetSize() * minidump_thread_size
;
414 // save for the ability to set up RVA
415 size_t size_before
= GetCurrentDataEndOffset();
417 AddDirectory(StreamType::ThreadList
, thread_stream_size
);
419 llvm::support::ulittle32_t thread_count
=
420 static_cast<llvm::support::ulittle32_t
>(thread_list
.GetSize());
421 m_data
.AppendData(&thread_count
, sizeof(llvm::support::ulittle32_t
));
423 DataBufferHeap helper_data
;
425 const uint32_t num_threads
= thread_list
.GetSize();
427 for (uint32_t thread_idx
= 0; thread_idx
< num_threads
; ++thread_idx
) {
428 ThreadSP
thread_sp(thread_list
.GetThreadAtIndex(thread_idx
));
429 RegisterContextSP
reg_ctx_sp(thread_sp
->GetRegisterContext());
433 error
.SetErrorString("Unable to get the register context.");
436 RegisterContext
*reg_ctx
= reg_ctx_sp
.get();
437 auto thread_context
= GetThreadContext_64(reg_ctx
);
438 uint64_t rsp
= read_register_u64_raw(reg_ctx
, "rsp");
439 auto expected_address_range
= findStackHelper(process_sp
, rsp
);
441 if (!expected_address_range
) {
442 error
.SetErrorString("Unable to get the stack address.");
446 std::pair
<uint64_t, uint64_t> range
= std::move(*expected_address_range
);
447 uint64_t addr
= range
.first
;
448 uint64_t size
= range
.second
;
450 auto data_up
= std::make_unique
<DataBufferHeap
>(size
, 0);
451 const size_t stack_bytes_read
=
452 process_sp
->ReadMemory(addr
, data_up
->GetBytes(), size
, error
);
457 LocationDescriptor stack_memory
;
458 stack_memory
.DataSize
=
459 static_cast<llvm::support::ulittle32_t
>(stack_bytes_read
);
460 stack_memory
.RVA
= static_cast<llvm::support::ulittle32_t
>(
461 size_before
+ thread_stream_size
+ helper_data
.GetByteSize());
463 MemoryDescriptor stack
;
464 stack
.StartOfMemoryRange
= static_cast<llvm::support::ulittle64_t
>(addr
);
465 stack
.Memory
= stack_memory
;
467 helper_data
.AppendData(data_up
->GetBytes(), stack_bytes_read
);
469 LocationDescriptor thread_context_memory_locator
;
470 thread_context_memory_locator
.DataSize
=
471 static_cast<llvm::support::ulittle32_t
>(sizeof(thread_context
));
472 thread_context_memory_locator
.RVA
= static_cast<llvm::support::ulittle32_t
>(
473 size_before
+ thread_stream_size
+ helper_data
.GetByteSize());
475 helper_data
.AppendData(
477 sizeof(lldb_private::minidump::MinidumpContext_x86_64
));
479 llvm::minidump::Thread t
;
480 t
.ThreadId
= static_cast<llvm::support::ulittle32_t
>(thread_sp
->GetID());
481 t
.SuspendCount
= static_cast<llvm::support::ulittle32_t
>(
482 (thread_sp
->GetState() == StateType::eStateSuspended
) ? 1 : 0);
483 t
.PriorityClass
= static_cast<llvm::support::ulittle32_t
>(0);
484 t
.Priority
= static_cast<llvm::support::ulittle32_t
>(0);
485 t
.EnvironmentBlock
= static_cast<llvm::support::ulittle64_t
>(0);
486 t
.Stack
= stack
, t
.Context
= thread_context_memory_locator
;
488 m_data
.AppendData(&t
, sizeof(llvm::minidump::Thread
));
491 m_data
.AppendData(helper_data
.GetBytes(), helper_data
.GetByteSize());
495 Status
MinidumpFileBuilder::AddException(const lldb::ProcessSP
&process_sp
) {
497 lldb_private::ThreadList thread_list
= process_sp
->GetThreadList();
499 const uint32_t num_threads
= thread_list
.GetSize();
500 uint32_t stop_reason_thread_idx
= 0;
501 for (stop_reason_thread_idx
= 0; stop_reason_thread_idx
< num_threads
;
502 ++stop_reason_thread_idx
) {
503 ThreadSP
thread_sp(thread_list
.GetThreadAtIndex(stop_reason_thread_idx
));
504 StopInfoSP stop_info_sp
= thread_sp
->GetStopInfo();
506 if (stop_info_sp
&& stop_info_sp
->IsValid())
510 if (stop_reason_thread_idx
== num_threads
) {
511 error
.SetErrorString("No stop reason thread found.");
515 constexpr size_t minidump_exception_size
=
516 sizeof(llvm::minidump::ExceptionStream
);
517 AddDirectory(StreamType::Exception
, minidump_exception_size
);
518 size_t size_before
= GetCurrentDataEndOffset();
520 ThreadSP
thread_sp(thread_list
.GetThreadAtIndex(stop_reason_thread_idx
));
521 RegisterContextSP
reg_ctx_sp(thread_sp
->GetRegisterContext());
522 RegisterContext
*reg_ctx
= reg_ctx_sp
.get();
523 auto thread_context
= GetThreadContext_64(reg_ctx
);
524 StopInfoSP stop_info_sp
= thread_sp
->GetStopInfo();
526 DataBufferHeap helper_data
;
528 LocationDescriptor thread_context_memory_locator
;
529 thread_context_memory_locator
.DataSize
=
530 static_cast<llvm::support::ulittle32_t
>(sizeof(thread_context
));
531 thread_context_memory_locator
.RVA
= static_cast<llvm::support::ulittle32_t
>(
532 size_before
+ minidump_exception_size
+ helper_data
.GetByteSize());
534 helper_data
.AppendData(
535 &thread_context
, sizeof(lldb_private::minidump::MinidumpContext_x86_64
));
537 Exception exp_record
= {};
538 exp_record
.ExceptionCode
=
539 static_cast<llvm::support::ulittle32_t
>(stop_info_sp
->GetValue());
540 exp_record
.ExceptionFlags
= static_cast<llvm::support::ulittle32_t
>(0);
541 exp_record
.ExceptionRecord
= static_cast<llvm::support::ulittle64_t
>(0);
542 exp_record
.ExceptionAddress
= read_register_u64(reg_ctx
, "rip");
543 exp_record
.NumberParameters
= static_cast<llvm::support::ulittle32_t
>(0);
544 exp_record
.UnusedAlignment
= static_cast<llvm::support::ulittle32_t
>(0);
545 // exp_record.ExceptionInformation;
547 ExceptionStream exp_stream
;
548 exp_stream
.ThreadId
=
549 static_cast<llvm::support::ulittle32_t
>(thread_sp
->GetID());
550 exp_stream
.UnusedAlignment
= static_cast<llvm::support::ulittle32_t
>(0);
551 exp_stream
.ExceptionRecord
= exp_record
;
552 exp_stream
.ThreadContext
= thread_context_memory_locator
;
554 m_data
.AppendData(&exp_stream
, minidump_exception_size
);
555 m_data
.AppendData(helper_data
.GetBytes(), helper_data
.GetByteSize());
560 MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP
&process_sp
) {
564 error
.SetErrorString("Process doesn't support getting memory region info.");
568 // Get interesting addresses
569 std::vector
<size_t> interesting_addresses
;
570 auto thread_list
= process_sp
->GetThreadList();
571 for (size_t i
= 0; i
< thread_list
.GetSize(); ++i
) {
572 ThreadSP
thread_sp(thread_list
.GetThreadAtIndex(i
));
573 RegisterContextSP
reg_ctx_sp(thread_sp
->GetRegisterContext());
574 RegisterContext
*reg_ctx
= reg_ctx_sp
.get();
576 interesting_addresses
.push_back(read_register_u64(reg_ctx
, "rsp"));
577 interesting_addresses
.push_back(read_register_u64(reg_ctx
, "rip"));
580 DataBufferHeap helper_data
;
581 std::vector
<MemoryDescriptor
> mem_descriptors
;
583 std::set
<addr_t
> visited_region_base_addresses
;
584 for (size_t interesting_address
: interesting_addresses
) {
585 MemoryRegionInfo range_info
;
586 error
= process_sp
->GetMemoryRegionInfo(interesting_address
, range_info
);
587 // Skip failed memory region requests or any regions with no permissions.
588 if (error
.Fail() || range_info
.GetLLDBPermissions() == 0)
590 const addr_t addr
= range_info
.GetRange().GetRangeBase();
591 // Skip any regions we have already saved out.
592 if (visited_region_base_addresses
.insert(addr
).second
== false)
594 const addr_t size
= range_info
.GetRange().GetByteSize();
597 auto data_up
= std::make_unique
<DataBufferHeap
>(size
, 0);
598 const size_t bytes_read
=
599 process_sp
->ReadMemory(addr
, data_up
->GetBytes(), size
, error
);
602 // We have a good memory region with valid bytes to store.
603 LocationDescriptor memory_dump
;
604 memory_dump
.DataSize
= static_cast<llvm::support::ulittle32_t
>(bytes_read
);
606 static_cast<llvm::support::ulittle32_t
>(GetCurrentDataEndOffset());
607 MemoryDescriptor memory_desc
;
608 memory_desc
.StartOfMemoryRange
=
609 static_cast<llvm::support::ulittle64_t
>(addr
);
610 memory_desc
.Memory
= memory_dump
;
611 mem_descriptors
.push_back(memory_desc
);
612 m_data
.AppendData(data_up
->GetBytes(), bytes_read
);
615 AddDirectory(StreamType::MemoryList
,
616 sizeof(llvm::support::ulittle32_t
) +
617 mem_descriptors
.size() *
618 sizeof(llvm::minidump::MemoryDescriptor
));
619 llvm::support::ulittle32_t
memory_ranges_num(mem_descriptors
.size());
621 m_data
.AppendData(&memory_ranges_num
, sizeof(llvm::support::ulittle32_t
));
622 for (auto memory_descriptor
: mem_descriptors
) {
623 m_data
.AppendData(&memory_descriptor
,
624 sizeof(llvm::minidump::MemoryDescriptor
));
630 void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP
&process_sp
) {
631 AddDirectory(StreamType::MiscInfo
,
632 sizeof(lldb_private::minidump::MinidumpMiscInfo
));
634 lldb_private::minidump::MinidumpMiscInfo misc_info
;
635 misc_info
.size
= static_cast<llvm::support::ulittle32_t
>(
636 sizeof(lldb_private::minidump::MinidumpMiscInfo
));
637 // Default set flags1 to 0, in case that we will not be able to
638 // get any information
639 misc_info
.flags1
= static_cast<llvm::support::ulittle32_t
>(0);
641 lldb_private::ProcessInstanceInfo process_info
;
642 process_sp
->GetProcessInfo(process_info
);
643 if (process_info
.ProcessIDIsValid()) {
644 // Set flags1 to reflect that PID is filled in
646 static_cast<llvm::support::ulittle32_t
>(static_cast<uint32_t>(
647 lldb_private::minidump::MinidumpMiscInfoFlags::ProcessID
));
648 misc_info
.process_id
=
649 static_cast<llvm::support::ulittle32_t
>(process_info
.GetProcessID());
652 m_data
.AppendData(&misc_info
,
653 sizeof(lldb_private::minidump::MinidumpMiscInfo
));
656 std::unique_ptr
<llvm::MemoryBuffer
>
657 getFileStreamHelper(const std::string
&path
) {
658 auto maybe_stream
= llvm::MemoryBuffer::getFileAsStream(path
);
661 return std::move(maybe_stream
.get());
664 void MinidumpFileBuilder::AddLinuxFileStreams(
665 const lldb::ProcessSP
&process_sp
) {
666 std::vector
<std::pair
<StreamType
, std::string
>> files_with_stream_types
= {
667 {StreamType::LinuxCPUInfo
, "/proc/cpuinfo"},
668 {StreamType::LinuxLSBRelease
, "/etc/lsb-release"},
671 lldb_private::ProcessInstanceInfo process_info
;
672 process_sp
->GetProcessInfo(process_info
);
673 if (process_info
.ProcessIDIsValid()) {
674 lldb::pid_t pid
= process_info
.GetProcessID();
675 std::string pid_str
= std::to_string(pid
);
676 files_with_stream_types
.push_back(
677 {StreamType::LinuxProcStatus
, "/proc/" + pid_str
+ "/status"});
678 files_with_stream_types
.push_back(
679 {StreamType::LinuxCMDLine
, "/proc/" + pid_str
+ "/cmdline"});
680 files_with_stream_types
.push_back(
681 {StreamType::LinuxEnviron
, "/proc/" + pid_str
+ "/environ"});
682 files_with_stream_types
.push_back(
683 {StreamType::LinuxAuxv
, "/proc/" + pid_str
+ "/auxv"});
684 files_with_stream_types
.push_back(
685 {StreamType::LinuxMaps
, "/proc/" + pid_str
+ "/maps"});
686 files_with_stream_types
.push_back(
687 {StreamType::LinuxProcStat
, "/proc/" + pid_str
+ "/stat"});
688 files_with_stream_types
.push_back(
689 {StreamType::LinuxProcFD
, "/proc/" + pid_str
+ "/fd"});
692 for (const auto &entry
: files_with_stream_types
) {
693 StreamType stream
= entry
.first
;
694 std::string path
= entry
.second
;
695 auto memory_buffer
= getFileStreamHelper(path
);
698 size_t size
= memory_buffer
->getBufferSize();
701 AddDirectory(stream
, size
);
702 m_data
.AppendData(memory_buffer
->getBufferStart(), size
);
707 Status
MinidumpFileBuilder::Dump(lldb::FileUP
&core_file
) const {
708 constexpr size_t header_size
= sizeof(llvm::minidump::Header
);
709 constexpr size_t directory_size
= sizeof(llvm::minidump::Directory
);
712 llvm::minidump::Header header
;
713 header
.Signature
= static_cast<llvm::support::ulittle32_t
>(
714 llvm::minidump::Header::MagicSignature
);
715 header
.Version
= static_cast<llvm::support::ulittle32_t
>(
716 llvm::minidump::Header::MagicVersion
);
717 header
.NumberOfStreams
=
718 static_cast<llvm::support::ulittle32_t
>(GetDirectoriesNum());
719 header
.StreamDirectoryRVA
=
720 static_cast<llvm::support::ulittle32_t
>(GetCurrentDataEndOffset());
721 header
.Checksum
= static_cast<llvm::support::ulittle32_t
>(
722 0u), // not used in most of the writers
723 header
.TimeDateStamp
=
724 static_cast<llvm::support::ulittle32_t
>(std::time(nullptr));
726 static_cast<llvm::support::ulittle64_t
>(0u); // minidump normal flag
729 size_t bytes_written
;
731 bytes_written
= header_size
;
732 error
= core_file
->Write(&header
, bytes_written
);
733 if (error
.Fail() || bytes_written
!= header_size
) {
734 if (bytes_written
!= header_size
)
735 error
.SetErrorStringWithFormat(
736 "unable to write the header (written %zd/%zd)", bytes_written
,
742 bytes_written
= m_data
.GetByteSize();
743 error
= core_file
->Write(m_data
.GetBytes(), bytes_written
);
744 if (error
.Fail() || bytes_written
!= m_data
.GetByteSize()) {
745 if (bytes_written
!= m_data
.GetByteSize())
746 error
.SetErrorStringWithFormat(
747 "unable to write the data (written %zd/%" PRIu64
")", bytes_written
,
748 m_data
.GetByteSize());
753 for (const Directory
&dir
: m_directories
) {
754 bytes_written
= directory_size
;
755 error
= core_file
->Write(&dir
, bytes_written
);
756 if (error
.Fail() || bytes_written
!= directory_size
) {
757 if (bytes_written
!= directory_size
)
758 error
.SetErrorStringWithFormat(
759 "unable to write the directory (written %zd/%zd)", bytes_written
,
768 size_t MinidumpFileBuilder::GetDirectoriesNum() const {
769 return m_directories
.size();
772 size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const {
773 return sizeof(llvm::minidump::Header
) + m_data
.GetByteSize();