xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
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 
11349cc55cSDimitry Andric #include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
12349cc55cSDimitry Andric 
13349cc55cSDimitry Andric #include "lldb/Core/Module.h"
14349cc55cSDimitry Andric #include "lldb/Core/ModuleList.h"
15349cc55cSDimitry Andric #include "lldb/Core/Section.h"
16349cc55cSDimitry Andric #include "lldb/Target/MemoryRegionInfo.h"
17349cc55cSDimitry Andric #include "lldb/Target/Process.h"
18349cc55cSDimitry Andric #include "lldb/Target/RegisterContext.h"
19349cc55cSDimitry Andric #include "lldb/Target/StopInfo.h"
20349cc55cSDimitry Andric #include "lldb/Target/ThreadList.h"
21349cc55cSDimitry Andric #include "lldb/Utility/DataExtractor.h"
22349cc55cSDimitry Andric #include "lldb/Utility/RegisterValue.h"
23349cc55cSDimitry Andric 
24349cc55cSDimitry Andric #include "llvm/ADT/StringRef.h"
25349cc55cSDimitry Andric #include "llvm/BinaryFormat/Minidump.h"
26349cc55cSDimitry Andric #include "llvm/Support/ConvertUTF.h"
27349cc55cSDimitry Andric #include "llvm/Support/Error.h"
28349cc55cSDimitry Andric 
29349cc55cSDimitry Andric #include "Plugins/Process/minidump/MinidumpTypes.h"
30349cc55cSDimitry Andric 
31349cc55cSDimitry Andric #include <cinttypes>
32349cc55cSDimitry Andric 
33349cc55cSDimitry Andric using namespace lldb;
34349cc55cSDimitry Andric using namespace lldb_private;
35349cc55cSDimitry Andric using namespace llvm::minidump;
36349cc55cSDimitry Andric 
37349cc55cSDimitry Andric void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) {
38349cc55cSDimitry Andric   LocationDescriptor loc;
39349cc55cSDimitry Andric   loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size);
40349cc55cSDimitry Andric   // Stream will begin at the current end of data section
41349cc55cSDimitry Andric   loc.RVA = static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
42349cc55cSDimitry Andric 
43349cc55cSDimitry Andric   Directory dir;
44349cc55cSDimitry Andric   dir.Type = static_cast<llvm::support::little_t<StreamType>>(type);
45349cc55cSDimitry Andric   dir.Location = loc;
46349cc55cSDimitry Andric 
47349cc55cSDimitry Andric   m_directories.push_back(dir);
48349cc55cSDimitry Andric }
49349cc55cSDimitry Andric 
50349cc55cSDimitry Andric Status MinidumpFileBuilder::AddSystemInfo(const llvm::Triple &target_triple) {
51349cc55cSDimitry Andric   Status error;
52349cc55cSDimitry Andric   AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo));
53349cc55cSDimitry Andric 
54349cc55cSDimitry Andric   llvm::minidump::ProcessorArchitecture arch;
55349cc55cSDimitry Andric   switch (target_triple.getArch()) {
56349cc55cSDimitry Andric   case llvm::Triple::ArchType::x86_64:
57349cc55cSDimitry Andric     arch = ProcessorArchitecture::AMD64;
58349cc55cSDimitry Andric     break;
59349cc55cSDimitry Andric   case llvm::Triple::ArchType::x86:
60349cc55cSDimitry Andric     arch = ProcessorArchitecture::X86;
61349cc55cSDimitry Andric     break;
62349cc55cSDimitry Andric   case llvm::Triple::ArchType::arm:
63349cc55cSDimitry Andric     arch = ProcessorArchitecture::ARM;
64349cc55cSDimitry Andric     break;
65349cc55cSDimitry Andric   case llvm::Triple::ArchType::aarch64:
66349cc55cSDimitry Andric     arch = ProcessorArchitecture::ARM64;
67349cc55cSDimitry Andric     break;
68349cc55cSDimitry Andric   case llvm::Triple::ArchType::mips64:
69349cc55cSDimitry Andric   case llvm::Triple::ArchType::mips64el:
70349cc55cSDimitry Andric   case llvm::Triple::ArchType::mips:
71349cc55cSDimitry Andric   case llvm::Triple::ArchType::mipsel:
72349cc55cSDimitry Andric     arch = ProcessorArchitecture::MIPS;
73349cc55cSDimitry Andric     break;
74349cc55cSDimitry Andric   case llvm::Triple::ArchType::ppc64:
75349cc55cSDimitry Andric   case llvm::Triple::ArchType::ppc:
76349cc55cSDimitry Andric   case llvm::Triple::ArchType::ppc64le:
77349cc55cSDimitry Andric     arch = ProcessorArchitecture::PPC;
78349cc55cSDimitry Andric     break;
79349cc55cSDimitry Andric   default:
80349cc55cSDimitry Andric     error.SetErrorStringWithFormat("Architecture %s not supported.",
81349cc55cSDimitry Andric                                    target_triple.getArchName().str().c_str());
82349cc55cSDimitry Andric     return error;
83349cc55cSDimitry Andric   };
84349cc55cSDimitry Andric 
85349cc55cSDimitry Andric   llvm::support::little_t<OSPlatform> platform_id;
86349cc55cSDimitry Andric   switch (target_triple.getOS()) {
87349cc55cSDimitry Andric   case llvm::Triple::OSType::Linux:
88349cc55cSDimitry Andric     if (target_triple.getEnvironment() ==
89349cc55cSDimitry Andric         llvm::Triple::EnvironmentType::Android)
90349cc55cSDimitry Andric       platform_id = OSPlatform::Android;
91349cc55cSDimitry Andric     else
92349cc55cSDimitry Andric       platform_id = OSPlatform::Linux;
93349cc55cSDimitry Andric     break;
94349cc55cSDimitry Andric   case llvm::Triple::OSType::Win32:
95349cc55cSDimitry Andric     platform_id = OSPlatform::Win32NT;
96349cc55cSDimitry Andric     break;
97349cc55cSDimitry Andric   case llvm::Triple::OSType::MacOSX:
98349cc55cSDimitry Andric     platform_id = OSPlatform::MacOSX;
99349cc55cSDimitry Andric     break;
100349cc55cSDimitry Andric   case llvm::Triple::OSType::IOS:
101349cc55cSDimitry Andric     platform_id = OSPlatform::IOS;
102349cc55cSDimitry Andric     break;
103349cc55cSDimitry Andric   default:
104349cc55cSDimitry Andric     error.SetErrorStringWithFormat("OS %s not supported.",
105349cc55cSDimitry Andric                                    target_triple.getOSName().str().c_str());
106349cc55cSDimitry Andric     return error;
107349cc55cSDimitry Andric   };
108349cc55cSDimitry Andric 
109349cc55cSDimitry Andric   llvm::minidump::SystemInfo sys_info;
110349cc55cSDimitry Andric   sys_info.ProcessorArch =
111349cc55cSDimitry Andric       static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch);
112349cc55cSDimitry Andric   // Global offset to beginning of a csd_string in a data section
113349cc55cSDimitry Andric   sys_info.CSDVersionRVA = static_cast<llvm::support::ulittle32_t>(
114349cc55cSDimitry Andric       GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo));
115349cc55cSDimitry Andric   sys_info.PlatformId = platform_id;
116349cc55cSDimitry Andric   m_data.AppendData(&sys_info, sizeof(llvm::minidump::SystemInfo));
117349cc55cSDimitry Andric 
118*04eeddc0SDimitry Andric   std::string csd_string;
119349cc55cSDimitry Andric 
120349cc55cSDimitry Andric   error = WriteString(csd_string, &m_data);
121349cc55cSDimitry Andric   if (error.Fail()) {
122349cc55cSDimitry Andric     error.SetErrorString("Unable to convert the csd string to UTF16.");
123349cc55cSDimitry Andric     return error;
124349cc55cSDimitry Andric   }
125349cc55cSDimitry Andric 
126349cc55cSDimitry Andric   return error;
127349cc55cSDimitry Andric }
128349cc55cSDimitry Andric 
129349cc55cSDimitry Andric Status WriteString(const std::string &to_write,
130349cc55cSDimitry Andric                    lldb_private::DataBufferHeap *buffer) {
131349cc55cSDimitry Andric   Status error;
132349cc55cSDimitry Andric   // let the StringRef eat also null termination char
133349cc55cSDimitry Andric   llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1);
134349cc55cSDimitry Andric   llvm::SmallVector<llvm::UTF16, 128> to_write_utf16;
135349cc55cSDimitry Andric 
136349cc55cSDimitry Andric   bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16);
137349cc55cSDimitry Andric   if (!converted) {
138349cc55cSDimitry Andric     error.SetErrorStringWithFormat(
139349cc55cSDimitry Andric         "Unable to convert the string to UTF16. Failed to convert %s",
140349cc55cSDimitry Andric         to_write.c_str());
141349cc55cSDimitry Andric     return error;
142349cc55cSDimitry Andric   }
143349cc55cSDimitry Andric 
144349cc55cSDimitry Andric   // size of the UTF16 string should be written without the null termination
145349cc55cSDimitry Andric   // character that is stored in 2 bytes
146349cc55cSDimitry Andric   llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2);
147349cc55cSDimitry Andric 
148349cc55cSDimitry Andric   buffer->AppendData(&to_write_size, sizeof(llvm::support::ulittle32_t));
149349cc55cSDimitry Andric   buffer->AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes());
150349cc55cSDimitry Andric 
151349cc55cSDimitry Andric   return error;
152349cc55cSDimitry Andric }
153349cc55cSDimitry Andric 
154349cc55cSDimitry Andric llvm::Expected<uint64_t> getModuleFileSize(Target &target,
155349cc55cSDimitry Andric                                            const ModuleSP &mod) {
156349cc55cSDimitry Andric   SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();
157349cc55cSDimitry Andric   uint64_t SizeOfImage = 0;
158349cc55cSDimitry Andric 
159349cc55cSDimitry Andric   if (!sect_sp) {
160349cc55cSDimitry Andric     return llvm::createStringError(std::errc::operation_not_supported,
161349cc55cSDimitry Andric                                    "Couldn't obtain the section information.");
162349cc55cSDimitry Andric   }
163349cc55cSDimitry Andric   lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target);
164349cc55cSDimitry Andric   // Use memory size since zero fill sections, like ".bss", will be smaller on
165349cc55cSDimitry Andric   // disk.
166349cc55cSDimitry Andric   lldb::addr_t sect_size = sect_sp->GetByteSize();
167349cc55cSDimitry Andric   // This will usually be zero, but make sure to calculate the BaseOfImage
168349cc55cSDimitry Andric   // offset.
169349cc55cSDimitry Andric   const lldb::addr_t base_sect_offset =
170349cc55cSDimitry Andric       mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) -
171349cc55cSDimitry Andric       sect_addr;
172349cc55cSDimitry Andric   SizeOfImage = sect_size - base_sect_offset;
173349cc55cSDimitry Andric   lldb::addr_t next_sect_addr = sect_addr + sect_size;
174349cc55cSDimitry Andric   Address sect_so_addr;
175349cc55cSDimitry Andric   target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
176349cc55cSDimitry Andric   lldb::SectionSP next_sect_sp = sect_so_addr.GetSection();
177349cc55cSDimitry Andric   while (next_sect_sp &&
178349cc55cSDimitry Andric          next_sect_sp->GetLoadBaseAddress(&target) == next_sect_addr) {
179349cc55cSDimitry Andric     sect_size = sect_sp->GetByteSize();
180349cc55cSDimitry Andric     SizeOfImage += sect_size;
181349cc55cSDimitry Andric     next_sect_addr += sect_size;
182349cc55cSDimitry Andric     target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
183349cc55cSDimitry Andric     next_sect_sp = sect_so_addr.GetSection();
184349cc55cSDimitry Andric   }
185349cc55cSDimitry Andric 
186349cc55cSDimitry Andric   return SizeOfImage;
187349cc55cSDimitry Andric }
188349cc55cSDimitry Andric 
189349cc55cSDimitry Andric // ModuleList stream consists of a number of modules, followed by an array
190349cc55cSDimitry Andric // of llvm::minidump::Module's structures. Every structure informs about a
191349cc55cSDimitry Andric // single module. Additional data of variable length, such as module's names,
192349cc55cSDimitry Andric // are stored just after the ModuleList stream. The llvm::minidump::Module
193349cc55cSDimitry Andric // structures point to this helper data by global offset.
194349cc55cSDimitry Andric Status MinidumpFileBuilder::AddModuleList(Target &target) {
195349cc55cSDimitry Andric   constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module);
196349cc55cSDimitry Andric   Status error;
197349cc55cSDimitry Andric 
198349cc55cSDimitry Andric   const ModuleList &modules = target.GetImages();
199349cc55cSDimitry Andric   llvm::support::ulittle32_t modules_count =
200349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(modules.GetSize());
201349cc55cSDimitry Andric 
202349cc55cSDimitry Andric   // This helps us with getting the correct global offset in minidump
203349cc55cSDimitry Andric   // file later, when we will be setting up offsets from the
204349cc55cSDimitry Andric   // the llvm::minidump::Module's structures into helper data
205349cc55cSDimitry Andric   size_t size_before = GetCurrentDataEndOffset();
206349cc55cSDimitry Andric 
207349cc55cSDimitry Andric   // This is the size of the main part of the ModuleList stream.
208349cc55cSDimitry Andric   // It consists of a module number and corresponding number of
209349cc55cSDimitry Andric   // structs describing individual modules
210349cc55cSDimitry Andric   size_t module_stream_size =
211349cc55cSDimitry Andric       sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size;
212349cc55cSDimitry Andric 
213349cc55cSDimitry Andric   // Adding directory describing this stream.
214349cc55cSDimitry Andric   AddDirectory(StreamType::ModuleList, module_stream_size);
215349cc55cSDimitry Andric 
216349cc55cSDimitry Andric   m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t));
217349cc55cSDimitry Andric 
218349cc55cSDimitry Andric   // Temporary storage for the helper data (of variable length)
219349cc55cSDimitry Andric   // as these cannot be dumped to m_data before dumping entire
220349cc55cSDimitry Andric   // array of module structures.
221349cc55cSDimitry Andric   DataBufferHeap helper_data;
222349cc55cSDimitry Andric 
223349cc55cSDimitry Andric   for (size_t i = 0; i < modules_count; ++i) {
224349cc55cSDimitry Andric     ModuleSP mod = modules.GetModuleAtIndex(i);
225349cc55cSDimitry Andric     std::string module_name = mod->GetSpecificationDescription();
226349cc55cSDimitry Andric     auto maybe_mod_size = getModuleFileSize(target, mod);
227349cc55cSDimitry Andric     if (!maybe_mod_size) {
228349cc55cSDimitry Andric       error.SetErrorStringWithFormat("Unable to get the size of module %s.",
229349cc55cSDimitry Andric                                      module_name.c_str());
230349cc55cSDimitry Andric       return error;
231349cc55cSDimitry Andric     }
232349cc55cSDimitry Andric 
233349cc55cSDimitry Andric     uint64_t mod_size = std::move(*maybe_mod_size);
234349cc55cSDimitry Andric 
235349cc55cSDimitry Andric     llvm::support::ulittle32_t signature =
236349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(
237349cc55cSDimitry Andric             static_cast<uint32_t>(minidump::CvSignature::ElfBuildId));
238349cc55cSDimitry Andric     auto uuid = mod->GetUUID().GetBytes();
239349cc55cSDimitry Andric 
240349cc55cSDimitry Andric     VSFixedFileInfo info;
241349cc55cSDimitry Andric     info.Signature = static_cast<llvm::support::ulittle32_t>(0u);
242349cc55cSDimitry Andric     info.StructVersion = static_cast<llvm::support::ulittle32_t>(0u);
243349cc55cSDimitry Andric     info.FileVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
244349cc55cSDimitry Andric     info.FileVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
245349cc55cSDimitry Andric     info.ProductVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
246349cc55cSDimitry Andric     info.ProductVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
247349cc55cSDimitry Andric     info.FileFlagsMask = static_cast<llvm::support::ulittle32_t>(0u);
248349cc55cSDimitry Andric     info.FileFlags = static_cast<llvm::support::ulittle32_t>(0u);
249349cc55cSDimitry Andric     info.FileOS = static_cast<llvm::support::ulittle32_t>(0u);
250349cc55cSDimitry Andric     info.FileType = static_cast<llvm::support::ulittle32_t>(0u);
251349cc55cSDimitry Andric     info.FileSubtype = static_cast<llvm::support::ulittle32_t>(0u);
252349cc55cSDimitry Andric     info.FileDateHigh = static_cast<llvm::support::ulittle32_t>(0u);
253349cc55cSDimitry Andric     info.FileDateLow = static_cast<llvm::support::ulittle32_t>(0u);
254349cc55cSDimitry Andric 
255349cc55cSDimitry Andric     LocationDescriptor ld;
256349cc55cSDimitry Andric     ld.DataSize = static_cast<llvm::support::ulittle32_t>(0u);
257349cc55cSDimitry Andric     ld.RVA = static_cast<llvm::support::ulittle32_t>(0u);
258349cc55cSDimitry Andric 
259349cc55cSDimitry Andric     // Setting up LocationDescriptor for uuid string. The global offset into
260349cc55cSDimitry Andric     // minidump file is calculated.
261349cc55cSDimitry Andric     LocationDescriptor ld_cv;
262349cc55cSDimitry Andric     ld_cv.DataSize = static_cast<llvm::support::ulittle32_t>(
263349cc55cSDimitry Andric         sizeof(llvm::support::ulittle32_t) + uuid.size());
264349cc55cSDimitry Andric     ld_cv.RVA = static_cast<llvm::support::ulittle32_t>(
265349cc55cSDimitry Andric         size_before + module_stream_size + helper_data.GetByteSize());
266349cc55cSDimitry Andric 
267349cc55cSDimitry Andric     helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t));
268349cc55cSDimitry Andric     helper_data.AppendData(uuid.begin(), uuid.size());
269349cc55cSDimitry Andric 
270349cc55cSDimitry Andric     llvm::minidump::Module m;
271349cc55cSDimitry Andric     m.BaseOfImage = static_cast<llvm::support::ulittle64_t>(
272349cc55cSDimitry Andric         mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target));
273349cc55cSDimitry Andric     m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size);
274349cc55cSDimitry Andric     m.Checksum = static_cast<llvm::support::ulittle32_t>(0);
275*04eeddc0SDimitry Andric     m.TimeDateStamp =
276*04eeddc0SDimitry Andric         static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
277349cc55cSDimitry Andric     m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>(
278349cc55cSDimitry Andric         size_before + module_stream_size + helper_data.GetByteSize());
279349cc55cSDimitry Andric     m.VersionInfo = info;
280349cc55cSDimitry Andric     m.CvRecord = ld_cv;
281349cc55cSDimitry Andric     m.MiscRecord = ld;
282349cc55cSDimitry Andric 
283349cc55cSDimitry Andric     error = WriteString(module_name, &helper_data);
284349cc55cSDimitry Andric 
285349cc55cSDimitry Andric     if (error.Fail())
286349cc55cSDimitry Andric       return error;
287349cc55cSDimitry Andric 
288349cc55cSDimitry Andric     m_data.AppendData(&m, sizeof(llvm::minidump::Module));
289349cc55cSDimitry Andric   }
290349cc55cSDimitry Andric 
291349cc55cSDimitry Andric   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
292349cc55cSDimitry Andric   return error;
293349cc55cSDimitry Andric }
294349cc55cSDimitry Andric 
295349cc55cSDimitry Andric uint16_t read_register_u16_raw(RegisterContext *reg_ctx,
296349cc55cSDimitry Andric                                const std::string &reg_name) {
297349cc55cSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
298349cc55cSDimitry Andric   if (!reg_info)
299349cc55cSDimitry Andric     return 0;
300349cc55cSDimitry Andric   lldb_private::RegisterValue reg_value;
301349cc55cSDimitry Andric   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
302349cc55cSDimitry Andric   if (!success)
303349cc55cSDimitry Andric     return 0;
304349cc55cSDimitry Andric   return reg_value.GetAsUInt16();
305349cc55cSDimitry Andric }
306349cc55cSDimitry Andric 
307349cc55cSDimitry Andric uint32_t read_register_u32_raw(RegisterContext *reg_ctx,
308349cc55cSDimitry Andric                                const std::string &reg_name) {
309349cc55cSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
310349cc55cSDimitry Andric   if (!reg_info)
311349cc55cSDimitry Andric     return 0;
312349cc55cSDimitry Andric   lldb_private::RegisterValue reg_value;
313349cc55cSDimitry Andric   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
314349cc55cSDimitry Andric   if (!success)
315349cc55cSDimitry Andric     return 0;
316349cc55cSDimitry Andric   return reg_value.GetAsUInt32();
317349cc55cSDimitry Andric }
318349cc55cSDimitry Andric 
319349cc55cSDimitry Andric uint64_t read_register_u64_raw(RegisterContext *reg_ctx,
320349cc55cSDimitry Andric                                const std::string &reg_name) {
321349cc55cSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
322349cc55cSDimitry Andric   if (!reg_info)
323349cc55cSDimitry Andric     return 0;
324349cc55cSDimitry Andric   lldb_private::RegisterValue reg_value;
325349cc55cSDimitry Andric   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
326349cc55cSDimitry Andric   if (!success)
327349cc55cSDimitry Andric     return 0;
328349cc55cSDimitry Andric   return reg_value.GetAsUInt64();
329349cc55cSDimitry Andric }
330349cc55cSDimitry Andric 
331349cc55cSDimitry Andric llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx,
332349cc55cSDimitry Andric                                              const std::string &reg_name) {
333349cc55cSDimitry Andric   return static_cast<llvm::support::ulittle16_t>(
334349cc55cSDimitry Andric       read_register_u16_raw(reg_ctx, reg_name));
335349cc55cSDimitry Andric }
336349cc55cSDimitry Andric 
337349cc55cSDimitry Andric llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx,
338349cc55cSDimitry Andric                                              const std::string &reg_name) {
339349cc55cSDimitry Andric   return static_cast<llvm::support::ulittle32_t>(
340349cc55cSDimitry Andric       read_register_u32_raw(reg_ctx, reg_name));
341349cc55cSDimitry Andric }
342349cc55cSDimitry Andric 
343349cc55cSDimitry Andric llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx,
344349cc55cSDimitry Andric                                              const std::string &reg_name) {
345349cc55cSDimitry Andric   return static_cast<llvm::support::ulittle64_t>(
346349cc55cSDimitry Andric       read_register_u64_raw(reg_ctx, reg_name));
347349cc55cSDimitry Andric }
348349cc55cSDimitry Andric 
349349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64
350349cc55cSDimitry Andric GetThreadContext_64(RegisterContext *reg_ctx) {
351349cc55cSDimitry Andric   lldb_private::minidump::MinidumpContext_x86_64 thread_context;
352349cc55cSDimitry Andric   thread_context.context_flags = static_cast<uint32_t>(
353349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag |
354349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::Control |
355349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::Segments |
356349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::Integer);
357349cc55cSDimitry Andric   thread_context.rax = read_register_u64(reg_ctx, "rax");
358349cc55cSDimitry Andric   thread_context.rbx = read_register_u64(reg_ctx, "rbx");
359349cc55cSDimitry Andric   thread_context.rcx = read_register_u64(reg_ctx, "rcx");
360349cc55cSDimitry Andric   thread_context.rdx = read_register_u64(reg_ctx, "rdx");
361349cc55cSDimitry Andric   thread_context.rdi = read_register_u64(reg_ctx, "rdi");
362349cc55cSDimitry Andric   thread_context.rsi = read_register_u64(reg_ctx, "rsi");
363349cc55cSDimitry Andric   thread_context.rbp = read_register_u64(reg_ctx, "rbp");
364349cc55cSDimitry Andric   thread_context.rsp = read_register_u64(reg_ctx, "rsp");
365349cc55cSDimitry Andric   thread_context.r8 = read_register_u64(reg_ctx, "r8");
366349cc55cSDimitry Andric   thread_context.r9 = read_register_u64(reg_ctx, "r9");
367349cc55cSDimitry Andric   thread_context.r10 = read_register_u64(reg_ctx, "r10");
368349cc55cSDimitry Andric   thread_context.r11 = read_register_u64(reg_ctx, "r11");
369349cc55cSDimitry Andric   thread_context.r12 = read_register_u64(reg_ctx, "r12");
370349cc55cSDimitry Andric   thread_context.r13 = read_register_u64(reg_ctx, "r13");
371349cc55cSDimitry Andric   thread_context.r14 = read_register_u64(reg_ctx, "r14");
372349cc55cSDimitry Andric   thread_context.r15 = read_register_u64(reg_ctx, "r15");
373349cc55cSDimitry Andric   thread_context.rip = read_register_u64(reg_ctx, "rip");
374349cc55cSDimitry Andric   thread_context.eflags = read_register_u32(reg_ctx, "rflags");
375349cc55cSDimitry Andric   thread_context.cs = read_register_u16(reg_ctx, "cs");
376349cc55cSDimitry Andric   thread_context.fs = read_register_u16(reg_ctx, "fs");
377349cc55cSDimitry Andric   thread_context.gs = read_register_u16(reg_ctx, "gs");
378349cc55cSDimitry Andric   thread_context.ss = read_register_u16(reg_ctx, "ss");
379349cc55cSDimitry Andric   thread_context.ds = read_register_u16(reg_ctx, "ds");
380349cc55cSDimitry Andric   return thread_context;
381349cc55cSDimitry Andric }
382349cc55cSDimitry Andric 
383349cc55cSDimitry Andric // Function returns start and size of the memory region that contains
384349cc55cSDimitry Andric // memory location pointed to by the current stack pointer.
385349cc55cSDimitry Andric llvm::Expected<std::pair<addr_t, addr_t>>
386349cc55cSDimitry Andric findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) {
387349cc55cSDimitry Andric   MemoryRegionInfo range_info;
388349cc55cSDimitry Andric   Status error = process_sp->GetMemoryRegionInfo(rsp, range_info);
389349cc55cSDimitry Andric   // Skip failed memory region requests or any regions with no permissions.
390349cc55cSDimitry Andric   if (error.Fail() || range_info.GetLLDBPermissions() == 0)
391349cc55cSDimitry Andric     return llvm::createStringError(
392349cc55cSDimitry Andric         std::errc::not_supported,
393349cc55cSDimitry Andric         "unable to load stack segment of the process");
394349cc55cSDimitry Andric 
395349cc55cSDimitry Andric   const addr_t addr = range_info.GetRange().GetRangeBase();
396349cc55cSDimitry Andric   const addr_t size = range_info.GetRange().GetByteSize();
397349cc55cSDimitry Andric 
398349cc55cSDimitry Andric   if (size == 0)
399349cc55cSDimitry Andric     return llvm::createStringError(std::errc::not_supported,
400349cc55cSDimitry Andric                                    "stack segment of the process is empty");
401349cc55cSDimitry Andric 
402349cc55cSDimitry Andric   return std::make_pair(addr, size);
403349cc55cSDimitry Andric }
404349cc55cSDimitry Andric 
405349cc55cSDimitry Andric Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
406349cc55cSDimitry Andric   constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread);
407349cc55cSDimitry Andric   lldb_private::ThreadList thread_list = process_sp->GetThreadList();
408349cc55cSDimitry Andric 
409349cc55cSDimitry Andric   // size of the entire thread stream consists of:
410349cc55cSDimitry Andric   // number of threads and threads array
411349cc55cSDimitry Andric   size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) +
412349cc55cSDimitry Andric                               thread_list.GetSize() * minidump_thread_size;
413349cc55cSDimitry Andric   // save for the ability to set up RVA
414349cc55cSDimitry Andric   size_t size_before = GetCurrentDataEndOffset();
415349cc55cSDimitry Andric 
416349cc55cSDimitry Andric   AddDirectory(StreamType::ThreadList, thread_stream_size);
417349cc55cSDimitry Andric 
418349cc55cSDimitry Andric   llvm::support::ulittle32_t thread_count =
419349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(thread_list.GetSize());
420349cc55cSDimitry Andric   m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t));
421349cc55cSDimitry Andric 
422349cc55cSDimitry Andric   DataBufferHeap helper_data;
423349cc55cSDimitry Andric 
424349cc55cSDimitry Andric   const uint32_t num_threads = thread_list.GetSize();
425349cc55cSDimitry Andric 
426349cc55cSDimitry Andric   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
427349cc55cSDimitry Andric     ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
428349cc55cSDimitry Andric     RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
429349cc55cSDimitry Andric     Status error;
430349cc55cSDimitry Andric 
431349cc55cSDimitry Andric     if (!reg_ctx_sp) {
432349cc55cSDimitry Andric       error.SetErrorString("Unable to get the register context.");
433349cc55cSDimitry Andric       return error;
434349cc55cSDimitry Andric     }
435349cc55cSDimitry Andric     RegisterContext *reg_ctx = reg_ctx_sp.get();
436349cc55cSDimitry Andric     auto thread_context = GetThreadContext_64(reg_ctx);
437349cc55cSDimitry Andric     uint64_t rsp = read_register_u64_raw(reg_ctx, "rsp");
438349cc55cSDimitry Andric     auto expected_address_range = findStackHelper(process_sp, rsp);
439349cc55cSDimitry Andric 
440349cc55cSDimitry Andric     if (!expected_address_range) {
441349cc55cSDimitry Andric       error.SetErrorString("Unable to get the stack address.");
442349cc55cSDimitry Andric       return error;
443349cc55cSDimitry Andric     }
444349cc55cSDimitry Andric 
445349cc55cSDimitry Andric     std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range);
446349cc55cSDimitry Andric     uint64_t addr = range.first;
447349cc55cSDimitry Andric     uint64_t size = range.second;
448349cc55cSDimitry Andric 
449349cc55cSDimitry Andric     auto data_up = std::make_unique<DataBufferHeap>(size, 0);
450349cc55cSDimitry Andric     const size_t stack_bytes_read =
451349cc55cSDimitry Andric         process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
452349cc55cSDimitry Andric 
453349cc55cSDimitry Andric     if (error.Fail())
454349cc55cSDimitry Andric       return error;
455349cc55cSDimitry Andric 
456349cc55cSDimitry Andric     LocationDescriptor stack_memory;
457349cc55cSDimitry Andric     stack_memory.DataSize =
458349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(stack_bytes_read);
459349cc55cSDimitry Andric     stack_memory.RVA = static_cast<llvm::support::ulittle32_t>(
460349cc55cSDimitry Andric         size_before + thread_stream_size + helper_data.GetByteSize());
461349cc55cSDimitry Andric 
462349cc55cSDimitry Andric     MemoryDescriptor stack;
463349cc55cSDimitry Andric     stack.StartOfMemoryRange = static_cast<llvm::support::ulittle64_t>(addr);
464349cc55cSDimitry Andric     stack.Memory = stack_memory;
465349cc55cSDimitry Andric 
466349cc55cSDimitry Andric     helper_data.AppendData(data_up->GetBytes(), stack_bytes_read);
467349cc55cSDimitry Andric 
468349cc55cSDimitry Andric     LocationDescriptor thread_context_memory_locator;
469349cc55cSDimitry Andric     thread_context_memory_locator.DataSize =
470349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(sizeof(thread_context));
471349cc55cSDimitry Andric     thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(
472349cc55cSDimitry Andric         size_before + thread_stream_size + helper_data.GetByteSize());
473349cc55cSDimitry Andric 
474349cc55cSDimitry Andric     helper_data.AppendData(
475349cc55cSDimitry Andric         &thread_context,
476349cc55cSDimitry Andric         sizeof(lldb_private::minidump::MinidumpContext_x86_64));
477349cc55cSDimitry Andric 
478349cc55cSDimitry Andric     llvm::minidump::Thread t;
479349cc55cSDimitry Andric     t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
480349cc55cSDimitry Andric     t.SuspendCount = static_cast<llvm::support::ulittle32_t>(
481349cc55cSDimitry Andric         (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0);
482349cc55cSDimitry Andric     t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0);
483349cc55cSDimitry Andric     t.Priority = static_cast<llvm::support::ulittle32_t>(0);
484349cc55cSDimitry Andric     t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0);
485349cc55cSDimitry Andric     t.Stack = stack, t.Context = thread_context_memory_locator;
486349cc55cSDimitry Andric 
487349cc55cSDimitry Andric     m_data.AppendData(&t, sizeof(llvm::minidump::Thread));
488349cc55cSDimitry Andric   }
489349cc55cSDimitry Andric 
490349cc55cSDimitry Andric   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
491349cc55cSDimitry Andric   return Status();
492349cc55cSDimitry Andric }
493349cc55cSDimitry Andric 
494349cc55cSDimitry Andric Status MinidumpFileBuilder::AddException(const lldb::ProcessSP &process_sp) {
495349cc55cSDimitry Andric   Status error;
496349cc55cSDimitry Andric   lldb_private::ThreadList thread_list = process_sp->GetThreadList();
497349cc55cSDimitry Andric 
498349cc55cSDimitry Andric   const uint32_t num_threads = thread_list.GetSize();
499349cc55cSDimitry Andric   uint32_t stop_reason_thread_idx = 0;
500349cc55cSDimitry Andric   for (stop_reason_thread_idx = 0; stop_reason_thread_idx < num_threads;
501349cc55cSDimitry Andric        ++stop_reason_thread_idx) {
502349cc55cSDimitry Andric     ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx));
503349cc55cSDimitry Andric     StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
504349cc55cSDimitry Andric 
505349cc55cSDimitry Andric     if (stop_info_sp && stop_info_sp->IsValid())
506349cc55cSDimitry Andric       break;
507349cc55cSDimitry Andric   }
508349cc55cSDimitry Andric 
509349cc55cSDimitry Andric   if (stop_reason_thread_idx == num_threads) {
510349cc55cSDimitry Andric     error.SetErrorString("No stop reason thread found.");
511349cc55cSDimitry Andric     return error;
512349cc55cSDimitry Andric   }
513349cc55cSDimitry Andric 
514349cc55cSDimitry Andric   constexpr size_t minidump_exception_size =
515349cc55cSDimitry Andric       sizeof(llvm::minidump::ExceptionStream);
516349cc55cSDimitry Andric   AddDirectory(StreamType::Exception, minidump_exception_size);
517349cc55cSDimitry Andric   size_t size_before = GetCurrentDataEndOffset();
518349cc55cSDimitry Andric 
519349cc55cSDimitry Andric   ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx));
520349cc55cSDimitry Andric   RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
521349cc55cSDimitry Andric   RegisterContext *reg_ctx = reg_ctx_sp.get();
522349cc55cSDimitry Andric   auto thread_context = GetThreadContext_64(reg_ctx);
523349cc55cSDimitry Andric   StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
524349cc55cSDimitry Andric 
525349cc55cSDimitry Andric   DataBufferHeap helper_data;
526349cc55cSDimitry Andric 
527349cc55cSDimitry Andric   LocationDescriptor thread_context_memory_locator;
528349cc55cSDimitry Andric   thread_context_memory_locator.DataSize =
529349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(sizeof(thread_context));
530349cc55cSDimitry Andric   thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(
531349cc55cSDimitry Andric       size_before + minidump_exception_size + helper_data.GetByteSize());
532349cc55cSDimitry Andric 
533349cc55cSDimitry Andric   helper_data.AppendData(
534349cc55cSDimitry Andric       &thread_context, sizeof(lldb_private::minidump::MinidumpContext_x86_64));
535349cc55cSDimitry Andric 
536349cc55cSDimitry Andric   Exception exp_record;
537349cc55cSDimitry Andric   exp_record.ExceptionCode =
538349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());
539349cc55cSDimitry Andric   exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0);
540349cc55cSDimitry Andric   exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0);
541349cc55cSDimitry Andric   exp_record.ExceptionAddress = read_register_u64(reg_ctx, "rip");
542349cc55cSDimitry Andric   exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0);
543349cc55cSDimitry Andric   exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
544349cc55cSDimitry Andric   // exp_record.ExceptionInformation;
545349cc55cSDimitry Andric 
546349cc55cSDimitry Andric   ExceptionStream exp_stream;
547349cc55cSDimitry Andric   exp_stream.ThreadId =
548349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
549349cc55cSDimitry Andric   exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
550349cc55cSDimitry Andric   exp_stream.ExceptionRecord = exp_record;
551349cc55cSDimitry Andric   exp_stream.ThreadContext = thread_context_memory_locator;
552349cc55cSDimitry Andric 
553349cc55cSDimitry Andric   m_data.AppendData(&exp_stream, minidump_exception_size);
554349cc55cSDimitry Andric   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
555349cc55cSDimitry Andric   return error;
556349cc55cSDimitry Andric }
557349cc55cSDimitry Andric 
558349cc55cSDimitry Andric lldb_private::Status
559349cc55cSDimitry Andric MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp) {
560349cc55cSDimitry Andric   Status error;
561349cc55cSDimitry Andric 
562349cc55cSDimitry Andric   if (error.Fail()) {
563349cc55cSDimitry Andric     error.SetErrorString("Process doesn't support getting memory region info.");
564349cc55cSDimitry Andric     return error;
565349cc55cSDimitry Andric   }
566349cc55cSDimitry Andric 
567349cc55cSDimitry Andric   // Get interesting addresses
568349cc55cSDimitry Andric   std::vector<size_t> interesting_addresses;
569349cc55cSDimitry Andric   auto thread_list = process_sp->GetThreadList();
570349cc55cSDimitry Andric   for (size_t i = 0; i < thread_list.GetSize(); ++i) {
571349cc55cSDimitry Andric     ThreadSP thread_sp(thread_list.GetThreadAtIndex(i));
572349cc55cSDimitry Andric     RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
573349cc55cSDimitry Andric     RegisterContext *reg_ctx = reg_ctx_sp.get();
574349cc55cSDimitry Andric 
575349cc55cSDimitry Andric     interesting_addresses.push_back(read_register_u64(reg_ctx, "rsp"));
576349cc55cSDimitry Andric     interesting_addresses.push_back(read_register_u64(reg_ctx, "rip"));
577349cc55cSDimitry Andric   }
578349cc55cSDimitry Andric 
579349cc55cSDimitry Andric   DataBufferHeap helper_data;
580349cc55cSDimitry Andric   std::vector<MemoryDescriptor> mem_descriptors;
581349cc55cSDimitry Andric 
582349cc55cSDimitry Andric   std::set<addr_t> visited_region_base_addresses;
583349cc55cSDimitry Andric   for (size_t interesting_address : interesting_addresses) {
584349cc55cSDimitry Andric     MemoryRegionInfo range_info;
585349cc55cSDimitry Andric     error = process_sp->GetMemoryRegionInfo(interesting_address, range_info);
586349cc55cSDimitry Andric     // Skip failed memory region requests or any regions with no permissions.
587349cc55cSDimitry Andric     if (error.Fail() || range_info.GetLLDBPermissions() == 0)
588349cc55cSDimitry Andric       continue;
589349cc55cSDimitry Andric     const addr_t addr = range_info.GetRange().GetRangeBase();
590349cc55cSDimitry Andric     // Skip any regions we have already saved out.
591349cc55cSDimitry Andric     if (visited_region_base_addresses.insert(addr).second == false)
592349cc55cSDimitry Andric       continue;
593349cc55cSDimitry Andric     const addr_t size = range_info.GetRange().GetByteSize();
594349cc55cSDimitry Andric     if (size == 0)
595349cc55cSDimitry Andric       continue;
596349cc55cSDimitry Andric     auto data_up = std::make_unique<DataBufferHeap>(size, 0);
597349cc55cSDimitry Andric     const size_t bytes_read =
598349cc55cSDimitry Andric         process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
599349cc55cSDimitry Andric     if (bytes_read == 0)
600349cc55cSDimitry Andric       continue;
601349cc55cSDimitry Andric     // We have a good memory region with valid bytes to store.
602349cc55cSDimitry Andric     LocationDescriptor memory_dump;
603349cc55cSDimitry Andric     memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(bytes_read);
604349cc55cSDimitry Andric     memory_dump.RVA =
605349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
606349cc55cSDimitry Andric     MemoryDescriptor memory_desc;
607349cc55cSDimitry Andric     memory_desc.StartOfMemoryRange =
608349cc55cSDimitry Andric         static_cast<llvm::support::ulittle64_t>(addr);
609349cc55cSDimitry Andric     memory_desc.Memory = memory_dump;
610349cc55cSDimitry Andric     mem_descriptors.push_back(memory_desc);
611349cc55cSDimitry Andric     m_data.AppendData(data_up->GetBytes(), bytes_read);
612349cc55cSDimitry Andric   }
613349cc55cSDimitry Andric 
614349cc55cSDimitry Andric   AddDirectory(StreamType::MemoryList,
615349cc55cSDimitry Andric                sizeof(llvm::support::ulittle32_t) +
616349cc55cSDimitry Andric                    mem_descriptors.size() *
617349cc55cSDimitry Andric                        sizeof(llvm::minidump::MemoryDescriptor));
618349cc55cSDimitry Andric   llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size());
619349cc55cSDimitry Andric 
620349cc55cSDimitry Andric   m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t));
621349cc55cSDimitry Andric   for (auto memory_descriptor : mem_descriptors) {
622349cc55cSDimitry Andric     m_data.AppendData(&memory_descriptor,
623349cc55cSDimitry Andric                       sizeof(llvm::minidump::MemoryDescriptor));
624349cc55cSDimitry Andric   }
625349cc55cSDimitry Andric 
626349cc55cSDimitry Andric   return error;
627349cc55cSDimitry Andric }
628349cc55cSDimitry Andric 
629349cc55cSDimitry Andric void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) {
630349cc55cSDimitry Andric   AddDirectory(StreamType::MiscInfo,
631349cc55cSDimitry Andric                sizeof(lldb_private::minidump::MinidumpMiscInfo));
632349cc55cSDimitry Andric 
633349cc55cSDimitry Andric   lldb_private::minidump::MinidumpMiscInfo misc_info;
634349cc55cSDimitry Andric   misc_info.size = static_cast<llvm::support::ulittle32_t>(
635349cc55cSDimitry Andric       sizeof(lldb_private::minidump::MinidumpMiscInfo));
636349cc55cSDimitry Andric   // Default set flags1 to 0, in case that we will not be able to
637349cc55cSDimitry Andric   // get any information
638349cc55cSDimitry Andric   misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0);
639349cc55cSDimitry Andric 
640349cc55cSDimitry Andric   lldb_private::ProcessInstanceInfo process_info;
641349cc55cSDimitry Andric   process_sp->GetProcessInfo(process_info);
642349cc55cSDimitry Andric   if (process_info.ProcessIDIsValid()) {
643349cc55cSDimitry Andric     // Set flags1 to reflect that PID is filled in
644349cc55cSDimitry Andric     misc_info.flags1 =
645349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>(
646349cc55cSDimitry Andric             lldb_private::minidump::MinidumpMiscInfoFlags::ProcessID));
647349cc55cSDimitry Andric     misc_info.process_id =
648349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID());
649349cc55cSDimitry Andric   }
650349cc55cSDimitry Andric 
651349cc55cSDimitry Andric   m_data.AppendData(&misc_info,
652349cc55cSDimitry Andric                     sizeof(lldb_private::minidump::MinidumpMiscInfo));
653349cc55cSDimitry Andric }
654349cc55cSDimitry Andric 
655349cc55cSDimitry Andric std::unique_ptr<llvm::MemoryBuffer>
656349cc55cSDimitry Andric getFileStreamHelper(const std::string &path) {
657349cc55cSDimitry Andric   auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path);
658349cc55cSDimitry Andric   if (!maybe_stream)
659349cc55cSDimitry Andric     return nullptr;
660349cc55cSDimitry Andric   return std::move(maybe_stream.get());
661349cc55cSDimitry Andric }
662349cc55cSDimitry Andric 
663349cc55cSDimitry Andric void MinidumpFileBuilder::AddLinuxFileStreams(
664349cc55cSDimitry Andric     const lldb::ProcessSP &process_sp) {
665349cc55cSDimitry Andric   std::vector<std::pair<StreamType, std::string>> files_with_stream_types = {
666349cc55cSDimitry Andric       {StreamType::LinuxCPUInfo, "/proc/cpuinfo"},
667349cc55cSDimitry Andric       {StreamType::LinuxLSBRelease, "/etc/lsb-release"},
668349cc55cSDimitry Andric   };
669349cc55cSDimitry Andric 
670349cc55cSDimitry Andric   lldb_private::ProcessInstanceInfo process_info;
671349cc55cSDimitry Andric   process_sp->GetProcessInfo(process_info);
672349cc55cSDimitry Andric   if (process_info.ProcessIDIsValid()) {
673349cc55cSDimitry Andric     lldb::pid_t pid = process_info.GetProcessID();
674349cc55cSDimitry Andric     std::string pid_str = std::to_string(pid);
675349cc55cSDimitry Andric     files_with_stream_types.push_back(
676349cc55cSDimitry Andric         {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"});
677349cc55cSDimitry Andric     files_with_stream_types.push_back(
678349cc55cSDimitry Andric         {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"});
679349cc55cSDimitry Andric     files_with_stream_types.push_back(
680349cc55cSDimitry Andric         {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"});
681349cc55cSDimitry Andric     files_with_stream_types.push_back(
682349cc55cSDimitry Andric         {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"});
683349cc55cSDimitry Andric     files_with_stream_types.push_back(
684349cc55cSDimitry Andric         {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"});
685349cc55cSDimitry Andric     files_with_stream_types.push_back(
686349cc55cSDimitry Andric         {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"});
687349cc55cSDimitry Andric     files_with_stream_types.push_back(
688349cc55cSDimitry Andric         {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"});
689349cc55cSDimitry Andric   }
690349cc55cSDimitry Andric 
691349cc55cSDimitry Andric   for (const auto &entry : files_with_stream_types) {
692349cc55cSDimitry Andric     StreamType stream = entry.first;
693349cc55cSDimitry Andric     std::string path = entry.second;
694349cc55cSDimitry Andric     auto memory_buffer = getFileStreamHelper(path);
695349cc55cSDimitry Andric 
696349cc55cSDimitry Andric     if (memory_buffer) {
697349cc55cSDimitry Andric       size_t size = memory_buffer->getBufferSize();
698349cc55cSDimitry Andric       if (size == 0)
699349cc55cSDimitry Andric         continue;
700349cc55cSDimitry Andric       AddDirectory(stream, size);
701349cc55cSDimitry Andric       m_data.AppendData(memory_buffer->getBufferStart(), size);
702349cc55cSDimitry Andric     }
703349cc55cSDimitry Andric   }
704349cc55cSDimitry Andric }
705349cc55cSDimitry Andric 
706349cc55cSDimitry Andric Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const {
707349cc55cSDimitry Andric   constexpr size_t header_size = sizeof(llvm::minidump::Header);
708349cc55cSDimitry Andric   constexpr size_t directory_size = sizeof(llvm::minidump::Directory);
709349cc55cSDimitry Andric 
710349cc55cSDimitry Andric   // write header
711349cc55cSDimitry Andric   llvm::minidump::Header header;
712349cc55cSDimitry Andric   header.Signature = static_cast<llvm::support::ulittle32_t>(
713349cc55cSDimitry Andric       llvm::minidump::Header::MagicSignature);
714349cc55cSDimitry Andric   header.Version = static_cast<llvm::support::ulittle32_t>(
715349cc55cSDimitry Andric       llvm::minidump::Header::MagicVersion);
716349cc55cSDimitry Andric   header.NumberOfStreams =
717349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(GetDirectoriesNum());
718349cc55cSDimitry Andric   header.StreamDirectoryRVA =
719349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
720349cc55cSDimitry Andric   header.Checksum = static_cast<llvm::support::ulittle32_t>(
721349cc55cSDimitry Andric       0u), // not used in most of the writers
722349cc55cSDimitry Andric       header.TimeDateStamp =
723*04eeddc0SDimitry Andric           static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
724349cc55cSDimitry Andric   header.Flags =
725349cc55cSDimitry Andric       static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag
726349cc55cSDimitry Andric 
727349cc55cSDimitry Andric   Status error;
728349cc55cSDimitry Andric   size_t bytes_written;
729349cc55cSDimitry Andric 
730349cc55cSDimitry Andric   bytes_written = header_size;
731349cc55cSDimitry Andric   error = core_file->Write(&header, bytes_written);
732349cc55cSDimitry Andric   if (error.Fail() || bytes_written != header_size) {
733349cc55cSDimitry Andric     if (bytes_written != header_size)
734349cc55cSDimitry Andric       error.SetErrorStringWithFormat(
735349cc55cSDimitry Andric           "unable to write the header (written %zd/%zd)", bytes_written,
736349cc55cSDimitry Andric           header_size);
737349cc55cSDimitry Andric     return error;
738349cc55cSDimitry Andric   }
739349cc55cSDimitry Andric 
740349cc55cSDimitry Andric   // write data
741349cc55cSDimitry Andric   bytes_written = m_data.GetByteSize();
742349cc55cSDimitry Andric   error = core_file->Write(m_data.GetBytes(), bytes_written);
743349cc55cSDimitry Andric   if (error.Fail() || bytes_written != m_data.GetByteSize()) {
744349cc55cSDimitry Andric     if (bytes_written != m_data.GetByteSize())
745349cc55cSDimitry Andric       error.SetErrorStringWithFormat(
746349cc55cSDimitry Andric           "unable to write the data (written %zd/%" PRIu64 ")", bytes_written,
747349cc55cSDimitry Andric           m_data.GetByteSize());
748349cc55cSDimitry Andric     return error;
749349cc55cSDimitry Andric   }
750349cc55cSDimitry Andric 
751349cc55cSDimitry Andric   // write directories
752349cc55cSDimitry Andric   for (const Directory &dir : m_directories) {
753349cc55cSDimitry Andric     bytes_written = directory_size;
754349cc55cSDimitry Andric     error = core_file->Write(&dir, bytes_written);
755349cc55cSDimitry Andric     if (error.Fail() || bytes_written != directory_size) {
756349cc55cSDimitry Andric       if (bytes_written != directory_size)
757349cc55cSDimitry Andric         error.SetErrorStringWithFormat(
758349cc55cSDimitry Andric             "unable to write the directory (written %zd/%zd)", bytes_written,
759349cc55cSDimitry Andric             directory_size);
760349cc55cSDimitry Andric       return error;
761349cc55cSDimitry Andric     }
762349cc55cSDimitry Andric   }
763349cc55cSDimitry Andric 
764349cc55cSDimitry Andric   return error;
765349cc55cSDimitry Andric }
766349cc55cSDimitry Andric 
767349cc55cSDimitry Andric size_t MinidumpFileBuilder::GetDirectoriesNum() const {
768349cc55cSDimitry Andric   return m_directories.size();
769349cc55cSDimitry Andric }
770349cc55cSDimitry Andric 
771349cc55cSDimitry Andric size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const {
772349cc55cSDimitry Andric   return sizeof(llvm::minidump::Header) + m_data.GetByteSize();
773349cc55cSDimitry Andric }
774