xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1349cc55cSDimitry Andric //===-- MinidumpFileBuilder.cpp -------------------------------------------===//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric 
9349cc55cSDimitry Andric #include "MinidumpFileBuilder.h"
10349cc55cSDimitry Andric 
11*5f757f3fSDimitry Andric #include "Plugins/Process/minidump/RegisterContextMinidump_ARM64.h"
12349cc55cSDimitry Andric #include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
13349cc55cSDimitry Andric 
14349cc55cSDimitry Andric #include "lldb/Core/Module.h"
15349cc55cSDimitry Andric #include "lldb/Core/ModuleList.h"
16349cc55cSDimitry Andric #include "lldb/Core/Section.h"
17349cc55cSDimitry Andric #include "lldb/Target/MemoryRegionInfo.h"
18349cc55cSDimitry Andric #include "lldb/Target/Process.h"
19349cc55cSDimitry Andric #include "lldb/Target/RegisterContext.h"
20349cc55cSDimitry Andric #include "lldb/Target/StopInfo.h"
21349cc55cSDimitry Andric #include "lldb/Target/ThreadList.h"
22349cc55cSDimitry Andric #include "lldb/Utility/DataExtractor.h"
23349cc55cSDimitry Andric #include "lldb/Utility/RegisterValue.h"
24349cc55cSDimitry Andric 
25349cc55cSDimitry Andric #include "llvm/ADT/StringRef.h"
26349cc55cSDimitry Andric #include "llvm/BinaryFormat/Minidump.h"
27349cc55cSDimitry Andric #include "llvm/Support/ConvertUTF.h"
28349cc55cSDimitry Andric #include "llvm/Support/Error.h"
29349cc55cSDimitry Andric 
30349cc55cSDimitry Andric #include "Plugins/Process/minidump/MinidumpTypes.h"
31349cc55cSDimitry Andric 
32349cc55cSDimitry Andric #include <cinttypes>
33349cc55cSDimitry Andric 
34349cc55cSDimitry Andric using namespace lldb;
35349cc55cSDimitry Andric using namespace lldb_private;
36349cc55cSDimitry Andric using namespace llvm::minidump;
37349cc55cSDimitry Andric 
38349cc55cSDimitry Andric void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) {
39349cc55cSDimitry Andric   LocationDescriptor loc;
40349cc55cSDimitry Andric   loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size);
41349cc55cSDimitry Andric   // Stream will begin at the current end of data section
42349cc55cSDimitry Andric   loc.RVA = static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
43349cc55cSDimitry Andric 
44349cc55cSDimitry Andric   Directory dir;
45349cc55cSDimitry Andric   dir.Type = static_cast<llvm::support::little_t<StreamType>>(type);
46349cc55cSDimitry Andric   dir.Location = loc;
47349cc55cSDimitry Andric 
48349cc55cSDimitry Andric   m_directories.push_back(dir);
49349cc55cSDimitry Andric }
50349cc55cSDimitry Andric 
51349cc55cSDimitry Andric Status MinidumpFileBuilder::AddSystemInfo(const llvm::Triple &target_triple) {
52349cc55cSDimitry Andric   Status error;
53349cc55cSDimitry Andric   AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo));
54349cc55cSDimitry Andric 
55349cc55cSDimitry Andric   llvm::minidump::ProcessorArchitecture arch;
56349cc55cSDimitry Andric   switch (target_triple.getArch()) {
57349cc55cSDimitry Andric   case llvm::Triple::ArchType::x86_64:
58349cc55cSDimitry Andric     arch = ProcessorArchitecture::AMD64;
59349cc55cSDimitry Andric     break;
60349cc55cSDimitry Andric   case llvm::Triple::ArchType::x86:
61349cc55cSDimitry Andric     arch = ProcessorArchitecture::X86;
62349cc55cSDimitry Andric     break;
63349cc55cSDimitry Andric   case llvm::Triple::ArchType::arm:
64349cc55cSDimitry Andric     arch = ProcessorArchitecture::ARM;
65349cc55cSDimitry Andric     break;
66349cc55cSDimitry Andric   case llvm::Triple::ArchType::aarch64:
67349cc55cSDimitry Andric     arch = ProcessorArchitecture::ARM64;
68349cc55cSDimitry Andric     break;
69349cc55cSDimitry Andric   case llvm::Triple::ArchType::mips64:
70349cc55cSDimitry Andric   case llvm::Triple::ArchType::mips64el:
71349cc55cSDimitry Andric   case llvm::Triple::ArchType::mips:
72349cc55cSDimitry Andric   case llvm::Triple::ArchType::mipsel:
73349cc55cSDimitry Andric     arch = ProcessorArchitecture::MIPS;
74349cc55cSDimitry Andric     break;
75349cc55cSDimitry Andric   case llvm::Triple::ArchType::ppc64:
76349cc55cSDimitry Andric   case llvm::Triple::ArchType::ppc:
77349cc55cSDimitry Andric   case llvm::Triple::ArchType::ppc64le:
78349cc55cSDimitry Andric     arch = ProcessorArchitecture::PPC;
79349cc55cSDimitry Andric     break;
80349cc55cSDimitry Andric   default:
81349cc55cSDimitry Andric     error.SetErrorStringWithFormat("Architecture %s not supported.",
82349cc55cSDimitry Andric                                    target_triple.getArchName().str().c_str());
83349cc55cSDimitry Andric     return error;
84349cc55cSDimitry Andric   };
85349cc55cSDimitry Andric 
86349cc55cSDimitry Andric   llvm::support::little_t<OSPlatform> platform_id;
87349cc55cSDimitry Andric   switch (target_triple.getOS()) {
88349cc55cSDimitry Andric   case llvm::Triple::OSType::Linux:
89349cc55cSDimitry Andric     if (target_triple.getEnvironment() ==
90349cc55cSDimitry Andric         llvm::Triple::EnvironmentType::Android)
91349cc55cSDimitry Andric       platform_id = OSPlatform::Android;
92349cc55cSDimitry Andric     else
93349cc55cSDimitry Andric       platform_id = OSPlatform::Linux;
94349cc55cSDimitry Andric     break;
95349cc55cSDimitry Andric   case llvm::Triple::OSType::Win32:
96349cc55cSDimitry Andric     platform_id = OSPlatform::Win32NT;
97349cc55cSDimitry Andric     break;
98349cc55cSDimitry Andric   case llvm::Triple::OSType::MacOSX:
99349cc55cSDimitry Andric     platform_id = OSPlatform::MacOSX;
100349cc55cSDimitry Andric     break;
101349cc55cSDimitry Andric   case llvm::Triple::OSType::IOS:
102349cc55cSDimitry Andric     platform_id = OSPlatform::IOS;
103349cc55cSDimitry Andric     break;
104349cc55cSDimitry Andric   default:
105349cc55cSDimitry Andric     error.SetErrorStringWithFormat("OS %s not supported.",
106349cc55cSDimitry Andric                                    target_triple.getOSName().str().c_str());
107349cc55cSDimitry Andric     return error;
108349cc55cSDimitry Andric   };
109349cc55cSDimitry Andric 
110349cc55cSDimitry Andric   llvm::minidump::SystemInfo sys_info;
111349cc55cSDimitry Andric   sys_info.ProcessorArch =
112349cc55cSDimitry Andric       static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch);
113349cc55cSDimitry Andric   // Global offset to beginning of a csd_string in a data section
114349cc55cSDimitry Andric   sys_info.CSDVersionRVA = static_cast<llvm::support::ulittle32_t>(
115349cc55cSDimitry Andric       GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo));
116349cc55cSDimitry Andric   sys_info.PlatformId = platform_id;
117349cc55cSDimitry Andric   m_data.AppendData(&sys_info, sizeof(llvm::minidump::SystemInfo));
118349cc55cSDimitry Andric 
11904eeddc0SDimitry Andric   std::string csd_string;
120349cc55cSDimitry Andric 
121349cc55cSDimitry Andric   error = WriteString(csd_string, &m_data);
122349cc55cSDimitry Andric   if (error.Fail()) {
123349cc55cSDimitry Andric     error.SetErrorString("Unable to convert the csd string to UTF16.");
124349cc55cSDimitry Andric     return error;
125349cc55cSDimitry Andric   }
126349cc55cSDimitry Andric 
127349cc55cSDimitry Andric   return error;
128349cc55cSDimitry Andric }
129349cc55cSDimitry Andric 
130349cc55cSDimitry Andric Status WriteString(const std::string &to_write,
131349cc55cSDimitry Andric                    lldb_private::DataBufferHeap *buffer) {
132349cc55cSDimitry Andric   Status error;
133349cc55cSDimitry Andric   // let the StringRef eat also null termination char
134349cc55cSDimitry Andric   llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1);
135349cc55cSDimitry Andric   llvm::SmallVector<llvm::UTF16, 128> to_write_utf16;
136349cc55cSDimitry Andric 
137349cc55cSDimitry Andric   bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16);
138349cc55cSDimitry Andric   if (!converted) {
139349cc55cSDimitry Andric     error.SetErrorStringWithFormat(
140349cc55cSDimitry Andric         "Unable to convert the string to UTF16. Failed to convert %s",
141349cc55cSDimitry Andric         to_write.c_str());
142349cc55cSDimitry Andric     return error;
143349cc55cSDimitry Andric   }
144349cc55cSDimitry Andric 
145349cc55cSDimitry Andric   // size of the UTF16 string should be written without the null termination
146349cc55cSDimitry Andric   // character that is stored in 2 bytes
147349cc55cSDimitry Andric   llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2);
148349cc55cSDimitry Andric 
149349cc55cSDimitry Andric   buffer->AppendData(&to_write_size, sizeof(llvm::support::ulittle32_t));
150349cc55cSDimitry Andric   buffer->AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes());
151349cc55cSDimitry Andric 
152349cc55cSDimitry Andric   return error;
153349cc55cSDimitry Andric }
154349cc55cSDimitry Andric 
155349cc55cSDimitry Andric llvm::Expected<uint64_t> getModuleFileSize(Target &target,
156349cc55cSDimitry Andric                                            const ModuleSP &mod) {
157349cc55cSDimitry Andric   SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();
158349cc55cSDimitry Andric   uint64_t SizeOfImage = 0;
159349cc55cSDimitry Andric 
160349cc55cSDimitry Andric   if (!sect_sp) {
161349cc55cSDimitry Andric     return llvm::createStringError(std::errc::operation_not_supported,
162349cc55cSDimitry Andric                                    "Couldn't obtain the section information.");
163349cc55cSDimitry Andric   }
164349cc55cSDimitry Andric   lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target);
165349cc55cSDimitry Andric   // Use memory size since zero fill sections, like ".bss", will be smaller on
166349cc55cSDimitry Andric   // disk.
167349cc55cSDimitry Andric   lldb::addr_t sect_size = sect_sp->GetByteSize();
168349cc55cSDimitry Andric   // This will usually be zero, but make sure to calculate the BaseOfImage
169349cc55cSDimitry Andric   // offset.
170349cc55cSDimitry Andric   const lldb::addr_t base_sect_offset =
171349cc55cSDimitry Andric       mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) -
172349cc55cSDimitry Andric       sect_addr;
173349cc55cSDimitry Andric   SizeOfImage = sect_size - base_sect_offset;
174349cc55cSDimitry Andric   lldb::addr_t next_sect_addr = sect_addr + sect_size;
175349cc55cSDimitry Andric   Address sect_so_addr;
176349cc55cSDimitry Andric   target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
177349cc55cSDimitry Andric   lldb::SectionSP next_sect_sp = sect_so_addr.GetSection();
178349cc55cSDimitry Andric   while (next_sect_sp &&
179349cc55cSDimitry Andric          next_sect_sp->GetLoadBaseAddress(&target) == next_sect_addr) {
180349cc55cSDimitry Andric     sect_size = sect_sp->GetByteSize();
181349cc55cSDimitry Andric     SizeOfImage += sect_size;
182349cc55cSDimitry Andric     next_sect_addr += sect_size;
183349cc55cSDimitry Andric     target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
184349cc55cSDimitry Andric     next_sect_sp = sect_so_addr.GetSection();
185349cc55cSDimitry Andric   }
186349cc55cSDimitry Andric 
187349cc55cSDimitry Andric   return SizeOfImage;
188349cc55cSDimitry Andric }
189349cc55cSDimitry Andric 
190349cc55cSDimitry Andric // ModuleList stream consists of a number of modules, followed by an array
191349cc55cSDimitry Andric // of llvm::minidump::Module's structures. Every structure informs about a
192349cc55cSDimitry Andric // single module. Additional data of variable length, such as module's names,
193349cc55cSDimitry Andric // are stored just after the ModuleList stream. The llvm::minidump::Module
194349cc55cSDimitry Andric // structures point to this helper data by global offset.
195349cc55cSDimitry Andric Status MinidumpFileBuilder::AddModuleList(Target &target) {
196349cc55cSDimitry Andric   constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module);
197349cc55cSDimitry Andric   Status error;
198349cc55cSDimitry Andric 
199349cc55cSDimitry Andric   const ModuleList &modules = target.GetImages();
200349cc55cSDimitry Andric   llvm::support::ulittle32_t modules_count =
201349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(modules.GetSize());
202349cc55cSDimitry Andric 
203349cc55cSDimitry Andric   // This helps us with getting the correct global offset in minidump
204349cc55cSDimitry Andric   // file later, when we will be setting up offsets from the
205349cc55cSDimitry Andric   // the llvm::minidump::Module's structures into helper data
206349cc55cSDimitry Andric   size_t size_before = GetCurrentDataEndOffset();
207349cc55cSDimitry Andric 
208349cc55cSDimitry Andric   // This is the size of the main part of the ModuleList stream.
209349cc55cSDimitry Andric   // It consists of a module number and corresponding number of
210349cc55cSDimitry Andric   // structs describing individual modules
211349cc55cSDimitry Andric   size_t module_stream_size =
212349cc55cSDimitry Andric       sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size;
213349cc55cSDimitry Andric 
214349cc55cSDimitry Andric   // Adding directory describing this stream.
215349cc55cSDimitry Andric   AddDirectory(StreamType::ModuleList, module_stream_size);
216349cc55cSDimitry Andric 
217349cc55cSDimitry Andric   m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t));
218349cc55cSDimitry Andric 
219349cc55cSDimitry Andric   // Temporary storage for the helper data (of variable length)
220349cc55cSDimitry Andric   // as these cannot be dumped to m_data before dumping entire
221349cc55cSDimitry Andric   // array of module structures.
222349cc55cSDimitry Andric   DataBufferHeap helper_data;
223349cc55cSDimitry Andric 
224349cc55cSDimitry Andric   for (size_t i = 0; i < modules_count; ++i) {
225349cc55cSDimitry Andric     ModuleSP mod = modules.GetModuleAtIndex(i);
226349cc55cSDimitry Andric     std::string module_name = mod->GetSpecificationDescription();
227349cc55cSDimitry Andric     auto maybe_mod_size = getModuleFileSize(target, mod);
228349cc55cSDimitry Andric     if (!maybe_mod_size) {
229349cc55cSDimitry Andric       error.SetErrorStringWithFormat("Unable to get the size of module %s.",
230349cc55cSDimitry Andric                                      module_name.c_str());
231349cc55cSDimitry Andric       return error;
232349cc55cSDimitry Andric     }
233349cc55cSDimitry Andric 
234349cc55cSDimitry Andric     uint64_t mod_size = std::move(*maybe_mod_size);
235349cc55cSDimitry Andric 
236349cc55cSDimitry Andric     llvm::support::ulittle32_t signature =
237349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(
238349cc55cSDimitry Andric             static_cast<uint32_t>(minidump::CvSignature::ElfBuildId));
239349cc55cSDimitry Andric     auto uuid = mod->GetUUID().GetBytes();
240349cc55cSDimitry Andric 
241349cc55cSDimitry Andric     VSFixedFileInfo info;
242349cc55cSDimitry Andric     info.Signature = static_cast<llvm::support::ulittle32_t>(0u);
243349cc55cSDimitry Andric     info.StructVersion = static_cast<llvm::support::ulittle32_t>(0u);
244349cc55cSDimitry Andric     info.FileVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
245349cc55cSDimitry Andric     info.FileVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
246349cc55cSDimitry Andric     info.ProductVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
247349cc55cSDimitry Andric     info.ProductVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
248349cc55cSDimitry Andric     info.FileFlagsMask = static_cast<llvm::support::ulittle32_t>(0u);
249349cc55cSDimitry Andric     info.FileFlags = static_cast<llvm::support::ulittle32_t>(0u);
250349cc55cSDimitry Andric     info.FileOS = static_cast<llvm::support::ulittle32_t>(0u);
251349cc55cSDimitry Andric     info.FileType = static_cast<llvm::support::ulittle32_t>(0u);
252349cc55cSDimitry Andric     info.FileSubtype = static_cast<llvm::support::ulittle32_t>(0u);
253349cc55cSDimitry Andric     info.FileDateHigh = static_cast<llvm::support::ulittle32_t>(0u);
254349cc55cSDimitry Andric     info.FileDateLow = static_cast<llvm::support::ulittle32_t>(0u);
255349cc55cSDimitry Andric 
256349cc55cSDimitry Andric     LocationDescriptor ld;
257349cc55cSDimitry Andric     ld.DataSize = static_cast<llvm::support::ulittle32_t>(0u);
258349cc55cSDimitry Andric     ld.RVA = static_cast<llvm::support::ulittle32_t>(0u);
259349cc55cSDimitry Andric 
260349cc55cSDimitry Andric     // Setting up LocationDescriptor for uuid string. The global offset into
261349cc55cSDimitry Andric     // minidump file is calculated.
262349cc55cSDimitry Andric     LocationDescriptor ld_cv;
263349cc55cSDimitry Andric     ld_cv.DataSize = static_cast<llvm::support::ulittle32_t>(
264349cc55cSDimitry Andric         sizeof(llvm::support::ulittle32_t) + uuid.size());
265349cc55cSDimitry Andric     ld_cv.RVA = static_cast<llvm::support::ulittle32_t>(
266349cc55cSDimitry Andric         size_before + module_stream_size + helper_data.GetByteSize());
267349cc55cSDimitry Andric 
268349cc55cSDimitry Andric     helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t));
269349cc55cSDimitry Andric     helper_data.AppendData(uuid.begin(), uuid.size());
270349cc55cSDimitry Andric 
271349cc55cSDimitry Andric     llvm::minidump::Module m;
272349cc55cSDimitry Andric     m.BaseOfImage = static_cast<llvm::support::ulittle64_t>(
273349cc55cSDimitry Andric         mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target));
274349cc55cSDimitry Andric     m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size);
275349cc55cSDimitry Andric     m.Checksum = static_cast<llvm::support::ulittle32_t>(0);
27604eeddc0SDimitry Andric     m.TimeDateStamp =
27704eeddc0SDimitry Andric         static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
278349cc55cSDimitry Andric     m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>(
279349cc55cSDimitry Andric         size_before + module_stream_size + helper_data.GetByteSize());
280349cc55cSDimitry Andric     m.VersionInfo = info;
281349cc55cSDimitry Andric     m.CvRecord = ld_cv;
282349cc55cSDimitry Andric     m.MiscRecord = ld;
283349cc55cSDimitry Andric 
284349cc55cSDimitry Andric     error = WriteString(module_name, &helper_data);
285349cc55cSDimitry Andric 
286349cc55cSDimitry Andric     if (error.Fail())
287349cc55cSDimitry Andric       return error;
288349cc55cSDimitry Andric 
289349cc55cSDimitry Andric     m_data.AppendData(&m, sizeof(llvm::minidump::Module));
290349cc55cSDimitry Andric   }
291349cc55cSDimitry Andric 
292349cc55cSDimitry Andric   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
293349cc55cSDimitry Andric   return error;
294349cc55cSDimitry Andric }
295349cc55cSDimitry Andric 
296349cc55cSDimitry Andric uint16_t read_register_u16_raw(RegisterContext *reg_ctx,
297*5f757f3fSDimitry Andric                                llvm::StringRef reg_name) {
298349cc55cSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
299349cc55cSDimitry Andric   if (!reg_info)
300349cc55cSDimitry Andric     return 0;
301349cc55cSDimitry Andric   lldb_private::RegisterValue reg_value;
302349cc55cSDimitry Andric   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
303349cc55cSDimitry Andric   if (!success)
304349cc55cSDimitry Andric     return 0;
305349cc55cSDimitry Andric   return reg_value.GetAsUInt16();
306349cc55cSDimitry Andric }
307349cc55cSDimitry Andric 
308349cc55cSDimitry Andric uint32_t read_register_u32_raw(RegisterContext *reg_ctx,
309*5f757f3fSDimitry Andric                                llvm::StringRef reg_name) {
310349cc55cSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
311349cc55cSDimitry Andric   if (!reg_info)
312349cc55cSDimitry Andric     return 0;
313349cc55cSDimitry Andric   lldb_private::RegisterValue reg_value;
314349cc55cSDimitry Andric   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
315349cc55cSDimitry Andric   if (!success)
316349cc55cSDimitry Andric     return 0;
317349cc55cSDimitry Andric   return reg_value.GetAsUInt32();
318349cc55cSDimitry Andric }
319349cc55cSDimitry Andric 
320349cc55cSDimitry Andric uint64_t read_register_u64_raw(RegisterContext *reg_ctx,
321*5f757f3fSDimitry Andric                                llvm::StringRef reg_name) {
322349cc55cSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
323349cc55cSDimitry Andric   if (!reg_info)
324349cc55cSDimitry Andric     return 0;
325349cc55cSDimitry Andric   lldb_private::RegisterValue reg_value;
326349cc55cSDimitry Andric   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
327349cc55cSDimitry Andric   if (!success)
328349cc55cSDimitry Andric     return 0;
329349cc55cSDimitry Andric   return reg_value.GetAsUInt64();
330349cc55cSDimitry Andric }
331349cc55cSDimitry Andric 
332349cc55cSDimitry Andric llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx,
333*5f757f3fSDimitry Andric                                              llvm::StringRef reg_name) {
334349cc55cSDimitry Andric   return static_cast<llvm::support::ulittle16_t>(
335349cc55cSDimitry Andric       read_register_u16_raw(reg_ctx, reg_name));
336349cc55cSDimitry Andric }
337349cc55cSDimitry Andric 
338349cc55cSDimitry Andric llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx,
339*5f757f3fSDimitry Andric                                              llvm::StringRef reg_name) {
340349cc55cSDimitry Andric   return static_cast<llvm::support::ulittle32_t>(
341349cc55cSDimitry Andric       read_register_u32_raw(reg_ctx, reg_name));
342349cc55cSDimitry Andric }
343349cc55cSDimitry Andric 
344349cc55cSDimitry Andric llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx,
345*5f757f3fSDimitry Andric                                              llvm::StringRef reg_name) {
346349cc55cSDimitry Andric   return static_cast<llvm::support::ulittle64_t>(
347349cc55cSDimitry Andric       read_register_u64_raw(reg_ctx, reg_name));
348349cc55cSDimitry Andric }
349349cc55cSDimitry Andric 
350*5f757f3fSDimitry Andric void read_register_u128(RegisterContext *reg_ctx, llvm::StringRef reg_name,
351*5f757f3fSDimitry Andric                         uint8_t *dst) {
352*5f757f3fSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
353*5f757f3fSDimitry Andric   if (reg_info) {
354*5f757f3fSDimitry Andric     lldb_private::RegisterValue reg_value;
355*5f757f3fSDimitry Andric     if (reg_ctx->ReadRegister(reg_info, reg_value)) {
356*5f757f3fSDimitry Andric       Status error;
357*5f757f3fSDimitry Andric       uint32_t bytes_copied = reg_value.GetAsMemoryData(
358*5f757f3fSDimitry Andric           *reg_info, dst, 16, lldb::ByteOrder::eByteOrderLittle, error);
359*5f757f3fSDimitry Andric       if (bytes_copied == 16)
360*5f757f3fSDimitry Andric         return;
361*5f757f3fSDimitry Andric     }
362*5f757f3fSDimitry Andric   }
363*5f757f3fSDimitry Andric   // If anything goes wrong, then zero out the register value.
364*5f757f3fSDimitry Andric   memset(dst, 0, 16);
365*5f757f3fSDimitry Andric }
366*5f757f3fSDimitry Andric 
367349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64
368*5f757f3fSDimitry Andric GetThreadContext_x86_64(RegisterContext *reg_ctx) {
369972a253aSDimitry Andric   lldb_private::minidump::MinidumpContext_x86_64 thread_context = {};
370fcaf7f86SDimitry Andric   thread_context.p1_home = {};
371349cc55cSDimitry Andric   thread_context.context_flags = static_cast<uint32_t>(
372349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag |
373349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::Control |
374349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::Segments |
375349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::Integer);
376349cc55cSDimitry Andric   thread_context.rax = read_register_u64(reg_ctx, "rax");
377349cc55cSDimitry Andric   thread_context.rbx = read_register_u64(reg_ctx, "rbx");
378349cc55cSDimitry Andric   thread_context.rcx = read_register_u64(reg_ctx, "rcx");
379349cc55cSDimitry Andric   thread_context.rdx = read_register_u64(reg_ctx, "rdx");
380349cc55cSDimitry Andric   thread_context.rdi = read_register_u64(reg_ctx, "rdi");
381349cc55cSDimitry Andric   thread_context.rsi = read_register_u64(reg_ctx, "rsi");
382349cc55cSDimitry Andric   thread_context.rbp = read_register_u64(reg_ctx, "rbp");
383349cc55cSDimitry Andric   thread_context.rsp = read_register_u64(reg_ctx, "rsp");
384349cc55cSDimitry Andric   thread_context.r8 = read_register_u64(reg_ctx, "r8");
385349cc55cSDimitry Andric   thread_context.r9 = read_register_u64(reg_ctx, "r9");
386349cc55cSDimitry Andric   thread_context.r10 = read_register_u64(reg_ctx, "r10");
387349cc55cSDimitry Andric   thread_context.r11 = read_register_u64(reg_ctx, "r11");
388349cc55cSDimitry Andric   thread_context.r12 = read_register_u64(reg_ctx, "r12");
389349cc55cSDimitry Andric   thread_context.r13 = read_register_u64(reg_ctx, "r13");
390349cc55cSDimitry Andric   thread_context.r14 = read_register_u64(reg_ctx, "r14");
391349cc55cSDimitry Andric   thread_context.r15 = read_register_u64(reg_ctx, "r15");
392349cc55cSDimitry Andric   thread_context.rip = read_register_u64(reg_ctx, "rip");
393349cc55cSDimitry Andric   thread_context.eflags = read_register_u32(reg_ctx, "rflags");
394349cc55cSDimitry Andric   thread_context.cs = read_register_u16(reg_ctx, "cs");
395349cc55cSDimitry Andric   thread_context.fs = read_register_u16(reg_ctx, "fs");
396349cc55cSDimitry Andric   thread_context.gs = read_register_u16(reg_ctx, "gs");
397349cc55cSDimitry Andric   thread_context.ss = read_register_u16(reg_ctx, "ss");
398349cc55cSDimitry Andric   thread_context.ds = read_register_u16(reg_ctx, "ds");
399349cc55cSDimitry Andric   return thread_context;
400349cc55cSDimitry Andric }
401349cc55cSDimitry Andric 
402*5f757f3fSDimitry Andric minidump::RegisterContextMinidump_ARM64::Context
403*5f757f3fSDimitry Andric GetThreadContext_ARM64(RegisterContext *reg_ctx) {
404*5f757f3fSDimitry Andric   minidump::RegisterContextMinidump_ARM64::Context thread_context = {};
405*5f757f3fSDimitry Andric   thread_context.context_flags = static_cast<uint32_t>(
406*5f757f3fSDimitry Andric       minidump::RegisterContextMinidump_ARM64::Flags::ARM64_Flag |
407*5f757f3fSDimitry Andric       minidump::RegisterContextMinidump_ARM64::Flags::Integer |
408*5f757f3fSDimitry Andric       minidump::RegisterContextMinidump_ARM64::Flags::FloatingPoint);
409*5f757f3fSDimitry Andric   char reg_name[16];
410*5f757f3fSDimitry Andric   for (uint32_t i = 0; i < 31; ++i) {
411*5f757f3fSDimitry Andric     snprintf(reg_name, sizeof(reg_name), "x%u", i);
412*5f757f3fSDimitry Andric     thread_context.x[i] = read_register_u64(reg_ctx, reg_name);
413*5f757f3fSDimitry Andric   }
414*5f757f3fSDimitry Andric   // Work around a bug in debugserver where "sp" on arm64 doesn't have the alt
415*5f757f3fSDimitry Andric   // name set to "x31"
416*5f757f3fSDimitry Andric   thread_context.x[31] = read_register_u64(reg_ctx, "sp");
417*5f757f3fSDimitry Andric   thread_context.pc = read_register_u64(reg_ctx, "pc");
418*5f757f3fSDimitry Andric   thread_context.cpsr = read_register_u32(reg_ctx, "cpsr");
419*5f757f3fSDimitry Andric   thread_context.fpsr = read_register_u32(reg_ctx, "fpsr");
420*5f757f3fSDimitry Andric   thread_context.fpcr = read_register_u32(reg_ctx, "fpcr");
421*5f757f3fSDimitry Andric   for (uint32_t i = 0; i < 32; ++i) {
422*5f757f3fSDimitry Andric     snprintf(reg_name, sizeof(reg_name), "v%u", i);
423*5f757f3fSDimitry Andric     read_register_u128(reg_ctx, reg_name, &thread_context.v[i * 16]);
424*5f757f3fSDimitry Andric   }
425*5f757f3fSDimitry Andric   return thread_context;
426*5f757f3fSDimitry Andric }
427*5f757f3fSDimitry Andric 
428*5f757f3fSDimitry Andric class ArchThreadContexts {
429*5f757f3fSDimitry Andric   llvm::Triple::ArchType m_arch;
430*5f757f3fSDimitry Andric   union {
431*5f757f3fSDimitry Andric     lldb_private::minidump::MinidumpContext_x86_64 x86_64;
432*5f757f3fSDimitry Andric     lldb_private::minidump::RegisterContextMinidump_ARM64::Context arm64;
433*5f757f3fSDimitry Andric   };
434*5f757f3fSDimitry Andric 
435*5f757f3fSDimitry Andric public:
436*5f757f3fSDimitry Andric   ArchThreadContexts(llvm::Triple::ArchType arch) : m_arch(arch) {}
437*5f757f3fSDimitry Andric 
438*5f757f3fSDimitry Andric   bool prepareRegisterContext(RegisterContext *reg_ctx) {
439*5f757f3fSDimitry Andric     switch (m_arch) {
440*5f757f3fSDimitry Andric     case llvm::Triple::ArchType::x86_64:
441*5f757f3fSDimitry Andric       x86_64 = GetThreadContext_x86_64(reg_ctx);
442*5f757f3fSDimitry Andric       return true;
443*5f757f3fSDimitry Andric     case llvm::Triple::ArchType::aarch64:
444*5f757f3fSDimitry Andric       arm64 = GetThreadContext_ARM64(reg_ctx);
445*5f757f3fSDimitry Andric       return true;
446*5f757f3fSDimitry Andric     default:
447*5f757f3fSDimitry Andric       break;
448*5f757f3fSDimitry Andric     }
449*5f757f3fSDimitry Andric     return false;
450*5f757f3fSDimitry Andric   }
451*5f757f3fSDimitry Andric 
452*5f757f3fSDimitry Andric   const void *data() const { return &x86_64; }
453*5f757f3fSDimitry Andric 
454*5f757f3fSDimitry Andric   size_t size() const {
455*5f757f3fSDimitry Andric     switch (m_arch) {
456*5f757f3fSDimitry Andric     case llvm::Triple::ArchType::x86_64:
457*5f757f3fSDimitry Andric       return sizeof(x86_64);
458*5f757f3fSDimitry Andric     case llvm::Triple::ArchType::aarch64:
459*5f757f3fSDimitry Andric       return sizeof(arm64);
460*5f757f3fSDimitry Andric     default:
461*5f757f3fSDimitry Andric       break;
462*5f757f3fSDimitry Andric     }
463*5f757f3fSDimitry Andric     return 0;
464*5f757f3fSDimitry Andric   }
465*5f757f3fSDimitry Andric };
466*5f757f3fSDimitry Andric 
467349cc55cSDimitry Andric // Function returns start and size of the memory region that contains
468349cc55cSDimitry Andric // memory location pointed to by the current stack pointer.
469349cc55cSDimitry Andric llvm::Expected<std::pair<addr_t, addr_t>>
470349cc55cSDimitry Andric findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) {
471349cc55cSDimitry Andric   MemoryRegionInfo range_info;
472349cc55cSDimitry Andric   Status error = process_sp->GetMemoryRegionInfo(rsp, range_info);
473349cc55cSDimitry Andric   // Skip failed memory region requests or any regions with no permissions.
474349cc55cSDimitry Andric   if (error.Fail() || range_info.GetLLDBPermissions() == 0)
475349cc55cSDimitry Andric     return llvm::createStringError(
476349cc55cSDimitry Andric         std::errc::not_supported,
477349cc55cSDimitry Andric         "unable to load stack segment of the process");
478349cc55cSDimitry Andric 
479349cc55cSDimitry Andric   const addr_t addr = range_info.GetRange().GetRangeBase();
480349cc55cSDimitry Andric   const addr_t size = range_info.GetRange().GetByteSize();
481349cc55cSDimitry Andric 
482349cc55cSDimitry Andric   if (size == 0)
483349cc55cSDimitry Andric     return llvm::createStringError(std::errc::not_supported,
484349cc55cSDimitry Andric                                    "stack segment of the process is empty");
485349cc55cSDimitry Andric 
486349cc55cSDimitry Andric   return std::make_pair(addr, size);
487349cc55cSDimitry Andric }
488349cc55cSDimitry Andric 
489349cc55cSDimitry Andric Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
490349cc55cSDimitry Andric   constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread);
491349cc55cSDimitry Andric   lldb_private::ThreadList thread_list = process_sp->GetThreadList();
492349cc55cSDimitry Andric 
493349cc55cSDimitry Andric   // size of the entire thread stream consists of:
494349cc55cSDimitry Andric   // number of threads and threads array
495349cc55cSDimitry Andric   size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) +
496349cc55cSDimitry Andric                               thread_list.GetSize() * minidump_thread_size;
497349cc55cSDimitry Andric   // save for the ability to set up RVA
498349cc55cSDimitry Andric   size_t size_before = GetCurrentDataEndOffset();
499349cc55cSDimitry Andric 
500349cc55cSDimitry Andric   AddDirectory(StreamType::ThreadList, thread_stream_size);
501349cc55cSDimitry Andric 
502349cc55cSDimitry Andric   llvm::support::ulittle32_t thread_count =
503349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(thread_list.GetSize());
504349cc55cSDimitry Andric   m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t));
505349cc55cSDimitry Andric 
506349cc55cSDimitry Andric   DataBufferHeap helper_data;
507349cc55cSDimitry Andric 
508349cc55cSDimitry Andric   const uint32_t num_threads = thread_list.GetSize();
509349cc55cSDimitry Andric 
510349cc55cSDimitry Andric   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
511349cc55cSDimitry Andric     ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
512349cc55cSDimitry Andric     RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
513349cc55cSDimitry Andric     Status error;
514349cc55cSDimitry Andric 
515349cc55cSDimitry Andric     if (!reg_ctx_sp) {
516349cc55cSDimitry Andric       error.SetErrorString("Unable to get the register context.");
517349cc55cSDimitry Andric       return error;
518349cc55cSDimitry Andric     }
519349cc55cSDimitry Andric     RegisterContext *reg_ctx = reg_ctx_sp.get();
520*5f757f3fSDimitry Andric     Target &target = process_sp->GetTarget();
521*5f757f3fSDimitry Andric     const ArchSpec &arch = target.GetArchitecture();
522*5f757f3fSDimitry Andric     ArchThreadContexts thread_context(arch.GetMachine());
523*5f757f3fSDimitry Andric     if (!thread_context.prepareRegisterContext(reg_ctx)) {
524*5f757f3fSDimitry Andric       error.SetErrorStringWithFormat(
525*5f757f3fSDimitry Andric           "architecture %s not supported.",
526*5f757f3fSDimitry Andric           arch.GetTriple().getArchName().str().c_str());
527*5f757f3fSDimitry Andric       return error;
528*5f757f3fSDimitry Andric     }
529*5f757f3fSDimitry Andric     uint64_t sp = reg_ctx->GetSP();
530*5f757f3fSDimitry Andric     auto expected_address_range = findStackHelper(process_sp, sp);
531349cc55cSDimitry Andric 
532349cc55cSDimitry Andric     if (!expected_address_range) {
533*5f757f3fSDimitry Andric       consumeError(expected_address_range.takeError());
534349cc55cSDimitry Andric       error.SetErrorString("Unable to get the stack address.");
535349cc55cSDimitry Andric       return error;
536349cc55cSDimitry Andric     }
537349cc55cSDimitry Andric 
538349cc55cSDimitry Andric     std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range);
539349cc55cSDimitry Andric     uint64_t addr = range.first;
540349cc55cSDimitry Andric     uint64_t size = range.second;
541349cc55cSDimitry Andric 
542349cc55cSDimitry Andric     auto data_up = std::make_unique<DataBufferHeap>(size, 0);
543349cc55cSDimitry Andric     const size_t stack_bytes_read =
544349cc55cSDimitry Andric         process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
545349cc55cSDimitry Andric 
546349cc55cSDimitry Andric     if (error.Fail())
547349cc55cSDimitry Andric       return error;
548349cc55cSDimitry Andric 
549349cc55cSDimitry Andric     LocationDescriptor stack_memory;
550349cc55cSDimitry Andric     stack_memory.DataSize =
551349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(stack_bytes_read);
552349cc55cSDimitry Andric     stack_memory.RVA = static_cast<llvm::support::ulittle32_t>(
553349cc55cSDimitry Andric         size_before + thread_stream_size + helper_data.GetByteSize());
554349cc55cSDimitry Andric 
555349cc55cSDimitry Andric     MemoryDescriptor stack;
556349cc55cSDimitry Andric     stack.StartOfMemoryRange = static_cast<llvm::support::ulittle64_t>(addr);
557349cc55cSDimitry Andric     stack.Memory = stack_memory;
558349cc55cSDimitry Andric 
559349cc55cSDimitry Andric     helper_data.AppendData(data_up->GetBytes(), stack_bytes_read);
560349cc55cSDimitry Andric 
561349cc55cSDimitry Andric     LocationDescriptor thread_context_memory_locator;
562349cc55cSDimitry Andric     thread_context_memory_locator.DataSize =
563*5f757f3fSDimitry Andric         static_cast<llvm::support::ulittle32_t>(thread_context.size());
564349cc55cSDimitry Andric     thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(
565349cc55cSDimitry Andric         size_before + thread_stream_size + helper_data.GetByteSize());
566*5f757f3fSDimitry Andric     // Cache thie thread context memory so we can reuse for exceptions.
567*5f757f3fSDimitry Andric     m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator;
568349cc55cSDimitry Andric 
569*5f757f3fSDimitry Andric     helper_data.AppendData(thread_context.data(), thread_context.size());
570349cc55cSDimitry Andric 
571349cc55cSDimitry Andric     llvm::minidump::Thread t;
572349cc55cSDimitry Andric     t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
573349cc55cSDimitry Andric     t.SuspendCount = static_cast<llvm::support::ulittle32_t>(
574349cc55cSDimitry Andric         (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0);
575349cc55cSDimitry Andric     t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0);
576349cc55cSDimitry Andric     t.Priority = static_cast<llvm::support::ulittle32_t>(0);
577349cc55cSDimitry Andric     t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0);
578349cc55cSDimitry Andric     t.Stack = stack, t.Context = thread_context_memory_locator;
579349cc55cSDimitry Andric 
580349cc55cSDimitry Andric     m_data.AppendData(&t, sizeof(llvm::minidump::Thread));
581349cc55cSDimitry Andric   }
582349cc55cSDimitry Andric 
583349cc55cSDimitry Andric   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
584349cc55cSDimitry Andric   return Status();
585349cc55cSDimitry Andric }
586349cc55cSDimitry Andric 
587*5f757f3fSDimitry Andric void MinidumpFileBuilder::AddExceptions(const lldb::ProcessSP &process_sp) {
588349cc55cSDimitry Andric   lldb_private::ThreadList thread_list = process_sp->GetThreadList();
589349cc55cSDimitry Andric 
590349cc55cSDimitry Andric   const uint32_t num_threads = thread_list.GetSize();
591*5f757f3fSDimitry Andric   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
592*5f757f3fSDimitry Andric     ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
593349cc55cSDimitry Andric     StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
594*5f757f3fSDimitry Andric     bool add_exception = false;
595*5f757f3fSDimitry Andric     if (stop_info_sp) {
596*5f757f3fSDimitry Andric       switch (stop_info_sp->GetStopReason()) {
597*5f757f3fSDimitry Andric       case eStopReasonSignal:
598*5f757f3fSDimitry Andric       case eStopReasonException:
599*5f757f3fSDimitry Andric         add_exception = true;
600*5f757f3fSDimitry Andric         break;
601*5f757f3fSDimitry Andric       default:
602349cc55cSDimitry Andric         break;
603349cc55cSDimitry Andric       }
604349cc55cSDimitry Andric     }
605*5f757f3fSDimitry Andric     if (add_exception) {
606349cc55cSDimitry Andric       constexpr size_t minidump_exception_size =
607349cc55cSDimitry Andric           sizeof(llvm::minidump::ExceptionStream);
608349cc55cSDimitry Andric       AddDirectory(StreamType::Exception, minidump_exception_size);
609349cc55cSDimitry Andric       StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
610*5f757f3fSDimitry Andric       RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
611972a253aSDimitry Andric       Exception exp_record = {};
612349cc55cSDimitry Andric       exp_record.ExceptionCode =
613349cc55cSDimitry Andric           static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());
614349cc55cSDimitry Andric       exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0);
615349cc55cSDimitry Andric       exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0);
616*5f757f3fSDimitry Andric       exp_record.ExceptionAddress = reg_ctx_sp->GetPC();
617349cc55cSDimitry Andric       exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0);
618349cc55cSDimitry Andric       exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
619349cc55cSDimitry Andric       // exp_record.ExceptionInformation;
620349cc55cSDimitry Andric 
621349cc55cSDimitry Andric       ExceptionStream exp_stream;
622349cc55cSDimitry Andric       exp_stream.ThreadId =
623349cc55cSDimitry Andric           static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
624349cc55cSDimitry Andric       exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
625349cc55cSDimitry Andric       exp_stream.ExceptionRecord = exp_record;
626*5f757f3fSDimitry Andric       auto Iter = m_tid_to_reg_ctx.find(thread_sp->GetID());
627*5f757f3fSDimitry Andric       if (Iter != m_tid_to_reg_ctx.end()) {
628*5f757f3fSDimitry Andric         exp_stream.ThreadContext = Iter->second;
629*5f757f3fSDimitry Andric       } else {
630*5f757f3fSDimitry Andric         exp_stream.ThreadContext.DataSize = 0;
631*5f757f3fSDimitry Andric         exp_stream.ThreadContext.RVA = 0;
632*5f757f3fSDimitry Andric       }
633349cc55cSDimitry Andric       m_data.AppendData(&exp_stream, minidump_exception_size);
634*5f757f3fSDimitry Andric     }
635*5f757f3fSDimitry Andric   }
636349cc55cSDimitry Andric }
637349cc55cSDimitry Andric 
638349cc55cSDimitry Andric lldb_private::Status
639*5f757f3fSDimitry Andric MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp,
640*5f757f3fSDimitry Andric                                    lldb::SaveCoreStyle core_style) {
641349cc55cSDimitry Andric   Status error;
642*5f757f3fSDimitry Andric   Process::CoreFileMemoryRanges core_ranges;
643*5f757f3fSDimitry Andric   error = process_sp->CalculateCoreFileSaveRanges(core_style, core_ranges);
644349cc55cSDimitry Andric   if (error.Fail()) {
645349cc55cSDimitry Andric     error.SetErrorString("Process doesn't support getting memory region info.");
646349cc55cSDimitry Andric     return error;
647349cc55cSDimitry Andric   }
648349cc55cSDimitry Andric 
649349cc55cSDimitry Andric   DataBufferHeap helper_data;
650349cc55cSDimitry Andric   std::vector<MemoryDescriptor> mem_descriptors;
651*5f757f3fSDimitry Andric   for (const auto &core_range : core_ranges) {
652*5f757f3fSDimitry Andric     // Skip empty memory regions or any regions with no permissions.
653*5f757f3fSDimitry Andric     if (core_range.range.empty() || core_range.lldb_permissions == 0)
654349cc55cSDimitry Andric       continue;
655*5f757f3fSDimitry Andric     const addr_t addr = core_range.range.start();
656*5f757f3fSDimitry Andric     const addr_t size = core_range.range.size();
657349cc55cSDimitry Andric     auto data_up = std::make_unique<DataBufferHeap>(size, 0);
658349cc55cSDimitry Andric     const size_t bytes_read =
659349cc55cSDimitry Andric         process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
660349cc55cSDimitry Andric     if (bytes_read == 0)
661349cc55cSDimitry Andric       continue;
662349cc55cSDimitry Andric     // We have a good memory region with valid bytes to store.
663349cc55cSDimitry Andric     LocationDescriptor memory_dump;
664349cc55cSDimitry Andric     memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(bytes_read);
665349cc55cSDimitry Andric     memory_dump.RVA =
666349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
667349cc55cSDimitry Andric     MemoryDescriptor memory_desc;
668349cc55cSDimitry Andric     memory_desc.StartOfMemoryRange =
669349cc55cSDimitry Andric         static_cast<llvm::support::ulittle64_t>(addr);
670349cc55cSDimitry Andric     memory_desc.Memory = memory_dump;
671349cc55cSDimitry Andric     mem_descriptors.push_back(memory_desc);
672349cc55cSDimitry Andric     m_data.AppendData(data_up->GetBytes(), bytes_read);
673349cc55cSDimitry Andric   }
674349cc55cSDimitry Andric 
675349cc55cSDimitry Andric   AddDirectory(StreamType::MemoryList,
676349cc55cSDimitry Andric                sizeof(llvm::support::ulittle32_t) +
677349cc55cSDimitry Andric                    mem_descriptors.size() *
678349cc55cSDimitry Andric                        sizeof(llvm::minidump::MemoryDescriptor));
679349cc55cSDimitry Andric   llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size());
680349cc55cSDimitry Andric 
681349cc55cSDimitry Andric   m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t));
682349cc55cSDimitry Andric   for (auto memory_descriptor : mem_descriptors) {
683349cc55cSDimitry Andric     m_data.AppendData(&memory_descriptor,
684349cc55cSDimitry Andric                       sizeof(llvm::minidump::MemoryDescriptor));
685349cc55cSDimitry Andric   }
686349cc55cSDimitry Andric 
687349cc55cSDimitry Andric   return error;
688349cc55cSDimitry Andric }
689349cc55cSDimitry Andric 
690349cc55cSDimitry Andric void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) {
691349cc55cSDimitry Andric   AddDirectory(StreamType::MiscInfo,
692349cc55cSDimitry Andric                sizeof(lldb_private::minidump::MinidumpMiscInfo));
693349cc55cSDimitry Andric 
694349cc55cSDimitry Andric   lldb_private::minidump::MinidumpMiscInfo misc_info;
695349cc55cSDimitry Andric   misc_info.size = static_cast<llvm::support::ulittle32_t>(
696349cc55cSDimitry Andric       sizeof(lldb_private::minidump::MinidumpMiscInfo));
697349cc55cSDimitry Andric   // Default set flags1 to 0, in case that we will not be able to
698349cc55cSDimitry Andric   // get any information
699349cc55cSDimitry Andric   misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0);
700349cc55cSDimitry Andric 
701349cc55cSDimitry Andric   lldb_private::ProcessInstanceInfo process_info;
702349cc55cSDimitry Andric   process_sp->GetProcessInfo(process_info);
703349cc55cSDimitry Andric   if (process_info.ProcessIDIsValid()) {
704349cc55cSDimitry Andric     // Set flags1 to reflect that PID is filled in
705349cc55cSDimitry Andric     misc_info.flags1 =
706349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>(
707349cc55cSDimitry Andric             lldb_private::minidump::MinidumpMiscInfoFlags::ProcessID));
708349cc55cSDimitry Andric     misc_info.process_id =
709349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID());
710349cc55cSDimitry Andric   }
711349cc55cSDimitry Andric 
712349cc55cSDimitry Andric   m_data.AppendData(&misc_info,
713349cc55cSDimitry Andric                     sizeof(lldb_private::minidump::MinidumpMiscInfo));
714349cc55cSDimitry Andric }
715349cc55cSDimitry Andric 
716349cc55cSDimitry Andric std::unique_ptr<llvm::MemoryBuffer>
717349cc55cSDimitry Andric getFileStreamHelper(const std::string &path) {
718349cc55cSDimitry Andric   auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path);
719349cc55cSDimitry Andric   if (!maybe_stream)
720349cc55cSDimitry Andric     return nullptr;
721349cc55cSDimitry Andric   return std::move(maybe_stream.get());
722349cc55cSDimitry Andric }
723349cc55cSDimitry Andric 
724349cc55cSDimitry Andric void MinidumpFileBuilder::AddLinuxFileStreams(
725349cc55cSDimitry Andric     const lldb::ProcessSP &process_sp) {
726349cc55cSDimitry Andric   std::vector<std::pair<StreamType, std::string>> files_with_stream_types = {
727349cc55cSDimitry Andric       {StreamType::LinuxCPUInfo, "/proc/cpuinfo"},
728349cc55cSDimitry Andric       {StreamType::LinuxLSBRelease, "/etc/lsb-release"},
729349cc55cSDimitry Andric   };
730349cc55cSDimitry Andric 
731349cc55cSDimitry Andric   lldb_private::ProcessInstanceInfo process_info;
732349cc55cSDimitry Andric   process_sp->GetProcessInfo(process_info);
733349cc55cSDimitry Andric   if (process_info.ProcessIDIsValid()) {
734349cc55cSDimitry Andric     lldb::pid_t pid = process_info.GetProcessID();
735349cc55cSDimitry Andric     std::string pid_str = std::to_string(pid);
736349cc55cSDimitry Andric     files_with_stream_types.push_back(
737349cc55cSDimitry Andric         {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"});
738349cc55cSDimitry Andric     files_with_stream_types.push_back(
739349cc55cSDimitry Andric         {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"});
740349cc55cSDimitry Andric     files_with_stream_types.push_back(
741349cc55cSDimitry Andric         {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"});
742349cc55cSDimitry Andric     files_with_stream_types.push_back(
743349cc55cSDimitry Andric         {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"});
744349cc55cSDimitry Andric     files_with_stream_types.push_back(
745349cc55cSDimitry Andric         {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"});
746349cc55cSDimitry Andric     files_with_stream_types.push_back(
747349cc55cSDimitry Andric         {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"});
748349cc55cSDimitry Andric     files_with_stream_types.push_back(
749349cc55cSDimitry Andric         {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"});
750349cc55cSDimitry Andric   }
751349cc55cSDimitry Andric 
752349cc55cSDimitry Andric   for (const auto &entry : files_with_stream_types) {
753349cc55cSDimitry Andric     StreamType stream = entry.first;
754349cc55cSDimitry Andric     std::string path = entry.second;
755349cc55cSDimitry Andric     auto memory_buffer = getFileStreamHelper(path);
756349cc55cSDimitry Andric 
757349cc55cSDimitry Andric     if (memory_buffer) {
758349cc55cSDimitry Andric       size_t size = memory_buffer->getBufferSize();
759349cc55cSDimitry Andric       if (size == 0)
760349cc55cSDimitry Andric         continue;
761349cc55cSDimitry Andric       AddDirectory(stream, size);
762349cc55cSDimitry Andric       m_data.AppendData(memory_buffer->getBufferStart(), size);
763349cc55cSDimitry Andric     }
764349cc55cSDimitry Andric   }
765349cc55cSDimitry Andric }
766349cc55cSDimitry Andric 
767349cc55cSDimitry Andric Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const {
768349cc55cSDimitry Andric   constexpr size_t header_size = sizeof(llvm::minidump::Header);
769349cc55cSDimitry Andric   constexpr size_t directory_size = sizeof(llvm::minidump::Directory);
770349cc55cSDimitry Andric 
771349cc55cSDimitry Andric   // write header
772349cc55cSDimitry Andric   llvm::minidump::Header header;
773349cc55cSDimitry Andric   header.Signature = static_cast<llvm::support::ulittle32_t>(
774349cc55cSDimitry Andric       llvm::minidump::Header::MagicSignature);
775349cc55cSDimitry Andric   header.Version = static_cast<llvm::support::ulittle32_t>(
776349cc55cSDimitry Andric       llvm::minidump::Header::MagicVersion);
777349cc55cSDimitry Andric   header.NumberOfStreams =
778349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(GetDirectoriesNum());
779349cc55cSDimitry Andric   header.StreamDirectoryRVA =
780349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
781349cc55cSDimitry Andric   header.Checksum = static_cast<llvm::support::ulittle32_t>(
782349cc55cSDimitry Andric       0u), // not used in most of the writers
783349cc55cSDimitry Andric       header.TimeDateStamp =
78404eeddc0SDimitry Andric           static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
785349cc55cSDimitry Andric   header.Flags =
786349cc55cSDimitry Andric       static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag
787349cc55cSDimitry Andric 
788349cc55cSDimitry Andric   Status error;
789349cc55cSDimitry Andric   size_t bytes_written;
790349cc55cSDimitry Andric 
791349cc55cSDimitry Andric   bytes_written = header_size;
792349cc55cSDimitry Andric   error = core_file->Write(&header, bytes_written);
793349cc55cSDimitry Andric   if (error.Fail() || bytes_written != header_size) {
794349cc55cSDimitry Andric     if (bytes_written != header_size)
795349cc55cSDimitry Andric       error.SetErrorStringWithFormat(
796349cc55cSDimitry Andric           "unable to write the header (written %zd/%zd)", bytes_written,
797349cc55cSDimitry Andric           header_size);
798349cc55cSDimitry Andric     return error;
799349cc55cSDimitry Andric   }
800349cc55cSDimitry Andric 
801349cc55cSDimitry Andric   // write data
802349cc55cSDimitry Andric   bytes_written = m_data.GetByteSize();
803349cc55cSDimitry Andric   error = core_file->Write(m_data.GetBytes(), bytes_written);
804349cc55cSDimitry Andric   if (error.Fail() || bytes_written != m_data.GetByteSize()) {
805349cc55cSDimitry Andric     if (bytes_written != m_data.GetByteSize())
806349cc55cSDimitry Andric       error.SetErrorStringWithFormat(
807349cc55cSDimitry Andric           "unable to write the data (written %zd/%" PRIu64 ")", bytes_written,
808349cc55cSDimitry Andric           m_data.GetByteSize());
809349cc55cSDimitry Andric     return error;
810349cc55cSDimitry Andric   }
811349cc55cSDimitry Andric 
812349cc55cSDimitry Andric   // write directories
813349cc55cSDimitry Andric   for (const Directory &dir : m_directories) {
814349cc55cSDimitry Andric     bytes_written = directory_size;
815349cc55cSDimitry Andric     error = core_file->Write(&dir, bytes_written);
816349cc55cSDimitry Andric     if (error.Fail() || bytes_written != directory_size) {
817349cc55cSDimitry Andric       if (bytes_written != directory_size)
818349cc55cSDimitry Andric         error.SetErrorStringWithFormat(
819349cc55cSDimitry Andric             "unable to write the directory (written %zd/%zd)", bytes_written,
820349cc55cSDimitry Andric             directory_size);
821349cc55cSDimitry Andric       return error;
822349cc55cSDimitry Andric     }
823349cc55cSDimitry Andric   }
824349cc55cSDimitry Andric 
825349cc55cSDimitry Andric   return error;
826349cc55cSDimitry Andric }
827349cc55cSDimitry Andric 
828349cc55cSDimitry Andric size_t MinidumpFileBuilder::GetDirectoriesNum() const {
829349cc55cSDimitry Andric   return m_directories.size();
830349cc55cSDimitry Andric }
831349cc55cSDimitry Andric 
832349cc55cSDimitry Andric size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const {
833349cc55cSDimitry Andric   return sizeof(llvm::minidump::Header) + m_data.GetByteSize();
834349cc55cSDimitry Andric }
835