xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
1*349cc55cSDimitry Andric //===-- MinidumpFileBuilder.cpp -------------------------------------------===//
2*349cc55cSDimitry Andric //
3*349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*349cc55cSDimitry Andric //
7*349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8*349cc55cSDimitry Andric 
9*349cc55cSDimitry Andric #include "MinidumpFileBuilder.h"
10*349cc55cSDimitry Andric 
11*349cc55cSDimitry Andric #include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
12*349cc55cSDimitry Andric 
13*349cc55cSDimitry Andric #include "lldb/Core/Module.h"
14*349cc55cSDimitry Andric #include "lldb/Core/ModuleList.h"
15*349cc55cSDimitry Andric #include "lldb/Core/Section.h"
16*349cc55cSDimitry Andric #include "lldb/Target/MemoryRegionInfo.h"
17*349cc55cSDimitry Andric #include "lldb/Target/Process.h"
18*349cc55cSDimitry Andric #include "lldb/Target/RegisterContext.h"
19*349cc55cSDimitry Andric #include "lldb/Target/StopInfo.h"
20*349cc55cSDimitry Andric #include "lldb/Target/ThreadList.h"
21*349cc55cSDimitry Andric #include "lldb/Utility/DataExtractor.h"
22*349cc55cSDimitry Andric #include "lldb/Utility/RegisterValue.h"
23*349cc55cSDimitry Andric 
24*349cc55cSDimitry Andric #include "llvm/ADT/StringRef.h"
25*349cc55cSDimitry Andric #include "llvm/BinaryFormat/Minidump.h"
26*349cc55cSDimitry Andric #include "llvm/Support/ConvertUTF.h"
27*349cc55cSDimitry Andric #include "llvm/Support/Error.h"
28*349cc55cSDimitry Andric 
29*349cc55cSDimitry Andric #include "Plugins/Process/minidump/MinidumpTypes.h"
30*349cc55cSDimitry Andric 
31*349cc55cSDimitry Andric #include <cinttypes>
32*349cc55cSDimitry Andric 
33*349cc55cSDimitry Andric using namespace lldb;
34*349cc55cSDimitry Andric using namespace lldb_private;
35*349cc55cSDimitry Andric using namespace llvm::minidump;
36*349cc55cSDimitry Andric 
37*349cc55cSDimitry Andric void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) {
38*349cc55cSDimitry Andric   LocationDescriptor loc;
39*349cc55cSDimitry Andric   loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size);
40*349cc55cSDimitry Andric   // Stream will begin at the current end of data section
41*349cc55cSDimitry Andric   loc.RVA = static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
42*349cc55cSDimitry Andric 
43*349cc55cSDimitry Andric   Directory dir;
44*349cc55cSDimitry Andric   dir.Type = static_cast<llvm::support::little_t<StreamType>>(type);
45*349cc55cSDimitry Andric   dir.Location = loc;
46*349cc55cSDimitry Andric 
47*349cc55cSDimitry Andric   m_directories.push_back(dir);
48*349cc55cSDimitry Andric }
49*349cc55cSDimitry Andric 
50*349cc55cSDimitry Andric Status MinidumpFileBuilder::AddSystemInfo(const llvm::Triple &target_triple) {
51*349cc55cSDimitry Andric   Status error;
52*349cc55cSDimitry Andric   AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo));
53*349cc55cSDimitry Andric 
54*349cc55cSDimitry Andric   llvm::minidump::ProcessorArchitecture arch;
55*349cc55cSDimitry Andric   switch (target_triple.getArch()) {
56*349cc55cSDimitry Andric   case llvm::Triple::ArchType::x86_64:
57*349cc55cSDimitry Andric     arch = ProcessorArchitecture::AMD64;
58*349cc55cSDimitry Andric     break;
59*349cc55cSDimitry Andric   case llvm::Triple::ArchType::x86:
60*349cc55cSDimitry Andric     arch = ProcessorArchitecture::X86;
61*349cc55cSDimitry Andric     break;
62*349cc55cSDimitry Andric   case llvm::Triple::ArchType::arm:
63*349cc55cSDimitry Andric     arch = ProcessorArchitecture::ARM;
64*349cc55cSDimitry Andric     break;
65*349cc55cSDimitry Andric   case llvm::Triple::ArchType::aarch64:
66*349cc55cSDimitry Andric     arch = ProcessorArchitecture::ARM64;
67*349cc55cSDimitry Andric     break;
68*349cc55cSDimitry Andric   case llvm::Triple::ArchType::mips64:
69*349cc55cSDimitry Andric   case llvm::Triple::ArchType::mips64el:
70*349cc55cSDimitry Andric   case llvm::Triple::ArchType::mips:
71*349cc55cSDimitry Andric   case llvm::Triple::ArchType::mipsel:
72*349cc55cSDimitry Andric     arch = ProcessorArchitecture::MIPS;
73*349cc55cSDimitry Andric     break;
74*349cc55cSDimitry Andric   case llvm::Triple::ArchType::ppc64:
75*349cc55cSDimitry Andric   case llvm::Triple::ArchType::ppc:
76*349cc55cSDimitry Andric   case llvm::Triple::ArchType::ppc64le:
77*349cc55cSDimitry Andric     arch = ProcessorArchitecture::PPC;
78*349cc55cSDimitry Andric     break;
79*349cc55cSDimitry Andric   default:
80*349cc55cSDimitry Andric     error.SetErrorStringWithFormat("Architecture %s not supported.",
81*349cc55cSDimitry Andric                                    target_triple.getArchName().str().c_str());
82*349cc55cSDimitry Andric     return error;
83*349cc55cSDimitry Andric   };
84*349cc55cSDimitry Andric 
85*349cc55cSDimitry Andric   llvm::support::little_t<OSPlatform> platform_id;
86*349cc55cSDimitry Andric   switch (target_triple.getOS()) {
87*349cc55cSDimitry Andric   case llvm::Triple::OSType::Linux:
88*349cc55cSDimitry Andric     if (target_triple.getEnvironment() ==
89*349cc55cSDimitry Andric         llvm::Triple::EnvironmentType::Android)
90*349cc55cSDimitry Andric       platform_id = OSPlatform::Android;
91*349cc55cSDimitry Andric     else
92*349cc55cSDimitry Andric       platform_id = OSPlatform::Linux;
93*349cc55cSDimitry Andric     break;
94*349cc55cSDimitry Andric   case llvm::Triple::OSType::Win32:
95*349cc55cSDimitry Andric     platform_id = OSPlatform::Win32NT;
96*349cc55cSDimitry Andric     break;
97*349cc55cSDimitry Andric   case llvm::Triple::OSType::MacOSX:
98*349cc55cSDimitry Andric     platform_id = OSPlatform::MacOSX;
99*349cc55cSDimitry Andric     break;
100*349cc55cSDimitry Andric   case llvm::Triple::OSType::IOS:
101*349cc55cSDimitry Andric     platform_id = OSPlatform::IOS;
102*349cc55cSDimitry Andric     break;
103*349cc55cSDimitry Andric   default:
104*349cc55cSDimitry Andric     error.SetErrorStringWithFormat("OS %s not supported.",
105*349cc55cSDimitry Andric                                    target_triple.getOSName().str().c_str());
106*349cc55cSDimitry Andric     return error;
107*349cc55cSDimitry Andric   };
108*349cc55cSDimitry Andric 
109*349cc55cSDimitry Andric   llvm::minidump::SystemInfo sys_info;
110*349cc55cSDimitry Andric   sys_info.ProcessorArch =
111*349cc55cSDimitry Andric       static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch);
112*349cc55cSDimitry Andric   // Global offset to beginning of a csd_string in a data section
113*349cc55cSDimitry Andric   sys_info.CSDVersionRVA = static_cast<llvm::support::ulittle32_t>(
114*349cc55cSDimitry Andric       GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo));
115*349cc55cSDimitry Andric   sys_info.PlatformId = platform_id;
116*349cc55cSDimitry Andric   m_data.AppendData(&sys_info, sizeof(llvm::minidump::SystemInfo));
117*349cc55cSDimitry Andric 
118*349cc55cSDimitry Andric   std::string csd_string = "";
119*349cc55cSDimitry Andric 
120*349cc55cSDimitry Andric   error = WriteString(csd_string, &m_data);
121*349cc55cSDimitry Andric   if (error.Fail()) {
122*349cc55cSDimitry Andric     error.SetErrorString("Unable to convert the csd string to UTF16.");
123*349cc55cSDimitry Andric     return error;
124*349cc55cSDimitry Andric   }
125*349cc55cSDimitry Andric 
126*349cc55cSDimitry Andric   return error;
127*349cc55cSDimitry Andric }
128*349cc55cSDimitry Andric 
129*349cc55cSDimitry Andric Status WriteString(const std::string &to_write,
130*349cc55cSDimitry Andric                    lldb_private::DataBufferHeap *buffer) {
131*349cc55cSDimitry Andric   Status error;
132*349cc55cSDimitry Andric   // let the StringRef eat also null termination char
133*349cc55cSDimitry Andric   llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1);
134*349cc55cSDimitry Andric   llvm::SmallVector<llvm::UTF16, 128> to_write_utf16;
135*349cc55cSDimitry Andric 
136*349cc55cSDimitry Andric   bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16);
137*349cc55cSDimitry Andric   if (!converted) {
138*349cc55cSDimitry Andric     error.SetErrorStringWithFormat(
139*349cc55cSDimitry Andric         "Unable to convert the string to UTF16. Failed to convert %s",
140*349cc55cSDimitry Andric         to_write.c_str());
141*349cc55cSDimitry Andric     return error;
142*349cc55cSDimitry Andric   }
143*349cc55cSDimitry Andric 
144*349cc55cSDimitry Andric   // size of the UTF16 string should be written without the null termination
145*349cc55cSDimitry Andric   // character that is stored in 2 bytes
146*349cc55cSDimitry Andric   llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2);
147*349cc55cSDimitry Andric 
148*349cc55cSDimitry Andric   buffer->AppendData(&to_write_size, sizeof(llvm::support::ulittle32_t));
149*349cc55cSDimitry Andric   buffer->AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes());
150*349cc55cSDimitry Andric 
151*349cc55cSDimitry Andric   return error;
152*349cc55cSDimitry Andric }
153*349cc55cSDimitry Andric 
154*349cc55cSDimitry Andric llvm::Expected<uint64_t> getModuleFileSize(Target &target,
155*349cc55cSDimitry Andric                                            const ModuleSP &mod) {
156*349cc55cSDimitry Andric   SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();
157*349cc55cSDimitry Andric   uint64_t SizeOfImage = 0;
158*349cc55cSDimitry Andric 
159*349cc55cSDimitry Andric   if (!sect_sp) {
160*349cc55cSDimitry Andric     return llvm::createStringError(std::errc::operation_not_supported,
161*349cc55cSDimitry Andric                                    "Couldn't obtain the section information.");
162*349cc55cSDimitry Andric   }
163*349cc55cSDimitry Andric   lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target);
164*349cc55cSDimitry Andric   // Use memory size since zero fill sections, like ".bss", will be smaller on
165*349cc55cSDimitry Andric   // disk.
166*349cc55cSDimitry Andric   lldb::addr_t sect_size = sect_sp->GetByteSize();
167*349cc55cSDimitry Andric   // This will usually be zero, but make sure to calculate the BaseOfImage
168*349cc55cSDimitry Andric   // offset.
169*349cc55cSDimitry Andric   const lldb::addr_t base_sect_offset =
170*349cc55cSDimitry Andric       mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) -
171*349cc55cSDimitry Andric       sect_addr;
172*349cc55cSDimitry Andric   SizeOfImage = sect_size - base_sect_offset;
173*349cc55cSDimitry Andric   lldb::addr_t next_sect_addr = sect_addr + sect_size;
174*349cc55cSDimitry Andric   Address sect_so_addr;
175*349cc55cSDimitry Andric   target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
176*349cc55cSDimitry Andric   lldb::SectionSP next_sect_sp = sect_so_addr.GetSection();
177*349cc55cSDimitry Andric   while (next_sect_sp &&
178*349cc55cSDimitry Andric          next_sect_sp->GetLoadBaseAddress(&target) == next_sect_addr) {
179*349cc55cSDimitry Andric     sect_size = sect_sp->GetByteSize();
180*349cc55cSDimitry Andric     SizeOfImage += sect_size;
181*349cc55cSDimitry Andric     next_sect_addr += sect_size;
182*349cc55cSDimitry Andric     target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
183*349cc55cSDimitry Andric     next_sect_sp = sect_so_addr.GetSection();
184*349cc55cSDimitry Andric   }
185*349cc55cSDimitry Andric 
186*349cc55cSDimitry Andric   return SizeOfImage;
187*349cc55cSDimitry Andric }
188*349cc55cSDimitry Andric 
189*349cc55cSDimitry Andric // ModuleList stream consists of a number of modules, followed by an array
190*349cc55cSDimitry Andric // of llvm::minidump::Module's structures. Every structure informs about a
191*349cc55cSDimitry Andric // single module. Additional data of variable length, such as module's names,
192*349cc55cSDimitry Andric // are stored just after the ModuleList stream. The llvm::minidump::Module
193*349cc55cSDimitry Andric // structures point to this helper data by global offset.
194*349cc55cSDimitry Andric Status MinidumpFileBuilder::AddModuleList(Target &target) {
195*349cc55cSDimitry Andric   constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module);
196*349cc55cSDimitry Andric   Status error;
197*349cc55cSDimitry Andric 
198*349cc55cSDimitry Andric   const ModuleList &modules = target.GetImages();
199*349cc55cSDimitry Andric   llvm::support::ulittle32_t modules_count =
200*349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(modules.GetSize());
201*349cc55cSDimitry Andric 
202*349cc55cSDimitry Andric   // This helps us with getting the correct global offset in minidump
203*349cc55cSDimitry Andric   // file later, when we will be setting up offsets from the
204*349cc55cSDimitry Andric   // the llvm::minidump::Module's structures into helper data
205*349cc55cSDimitry Andric   size_t size_before = GetCurrentDataEndOffset();
206*349cc55cSDimitry Andric 
207*349cc55cSDimitry Andric   // This is the size of the main part of the ModuleList stream.
208*349cc55cSDimitry Andric   // It consists of a module number and corresponding number of
209*349cc55cSDimitry Andric   // structs describing individual modules
210*349cc55cSDimitry Andric   size_t module_stream_size =
211*349cc55cSDimitry Andric       sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size;
212*349cc55cSDimitry Andric 
213*349cc55cSDimitry Andric   // Adding directory describing this stream.
214*349cc55cSDimitry Andric   AddDirectory(StreamType::ModuleList, module_stream_size);
215*349cc55cSDimitry Andric 
216*349cc55cSDimitry Andric   m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t));
217*349cc55cSDimitry Andric 
218*349cc55cSDimitry Andric   // Temporary storage for the helper data (of variable length)
219*349cc55cSDimitry Andric   // as these cannot be dumped to m_data before dumping entire
220*349cc55cSDimitry Andric   // array of module structures.
221*349cc55cSDimitry Andric   DataBufferHeap helper_data;
222*349cc55cSDimitry Andric 
223*349cc55cSDimitry Andric   for (size_t i = 0; i < modules_count; ++i) {
224*349cc55cSDimitry Andric     ModuleSP mod = modules.GetModuleAtIndex(i);
225*349cc55cSDimitry Andric     std::string module_name = mod->GetSpecificationDescription();
226*349cc55cSDimitry Andric     auto maybe_mod_size = getModuleFileSize(target, mod);
227*349cc55cSDimitry Andric     if (!maybe_mod_size) {
228*349cc55cSDimitry Andric       error.SetErrorStringWithFormat("Unable to get the size of module %s.",
229*349cc55cSDimitry Andric                                      module_name.c_str());
230*349cc55cSDimitry Andric       return error;
231*349cc55cSDimitry Andric     }
232*349cc55cSDimitry Andric 
233*349cc55cSDimitry Andric     uint64_t mod_size = std::move(*maybe_mod_size);
234*349cc55cSDimitry Andric 
235*349cc55cSDimitry Andric     llvm::support::ulittle32_t signature =
236*349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(
237*349cc55cSDimitry Andric             static_cast<uint32_t>(minidump::CvSignature::ElfBuildId));
238*349cc55cSDimitry Andric     auto uuid = mod->GetUUID().GetBytes();
239*349cc55cSDimitry Andric 
240*349cc55cSDimitry Andric     VSFixedFileInfo info;
241*349cc55cSDimitry Andric     info.Signature = static_cast<llvm::support::ulittle32_t>(0u);
242*349cc55cSDimitry Andric     info.StructVersion = static_cast<llvm::support::ulittle32_t>(0u);
243*349cc55cSDimitry Andric     info.FileVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
244*349cc55cSDimitry Andric     info.FileVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
245*349cc55cSDimitry Andric     info.ProductVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
246*349cc55cSDimitry Andric     info.ProductVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
247*349cc55cSDimitry Andric     info.FileFlagsMask = static_cast<llvm::support::ulittle32_t>(0u);
248*349cc55cSDimitry Andric     info.FileFlags = static_cast<llvm::support::ulittle32_t>(0u);
249*349cc55cSDimitry Andric     info.FileOS = static_cast<llvm::support::ulittle32_t>(0u);
250*349cc55cSDimitry Andric     info.FileType = static_cast<llvm::support::ulittle32_t>(0u);
251*349cc55cSDimitry Andric     info.FileSubtype = static_cast<llvm::support::ulittle32_t>(0u);
252*349cc55cSDimitry Andric     info.FileDateHigh = static_cast<llvm::support::ulittle32_t>(0u);
253*349cc55cSDimitry Andric     info.FileDateLow = static_cast<llvm::support::ulittle32_t>(0u);
254*349cc55cSDimitry Andric 
255*349cc55cSDimitry Andric     LocationDescriptor ld;
256*349cc55cSDimitry Andric     ld.DataSize = static_cast<llvm::support::ulittle32_t>(0u);
257*349cc55cSDimitry Andric     ld.RVA = static_cast<llvm::support::ulittle32_t>(0u);
258*349cc55cSDimitry Andric 
259*349cc55cSDimitry Andric     // Setting up LocationDescriptor for uuid string. The global offset into
260*349cc55cSDimitry Andric     // minidump file is calculated.
261*349cc55cSDimitry Andric     LocationDescriptor ld_cv;
262*349cc55cSDimitry Andric     ld_cv.DataSize = static_cast<llvm::support::ulittle32_t>(
263*349cc55cSDimitry Andric         sizeof(llvm::support::ulittle32_t) + uuid.size());
264*349cc55cSDimitry Andric     ld_cv.RVA = static_cast<llvm::support::ulittle32_t>(
265*349cc55cSDimitry Andric         size_before + module_stream_size + helper_data.GetByteSize());
266*349cc55cSDimitry Andric 
267*349cc55cSDimitry Andric     helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t));
268*349cc55cSDimitry Andric     helper_data.AppendData(uuid.begin(), uuid.size());
269*349cc55cSDimitry Andric 
270*349cc55cSDimitry Andric     llvm::minidump::Module m;
271*349cc55cSDimitry Andric     m.BaseOfImage = static_cast<llvm::support::ulittle64_t>(
272*349cc55cSDimitry Andric         mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target));
273*349cc55cSDimitry Andric     m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size);
274*349cc55cSDimitry Andric     m.Checksum = static_cast<llvm::support::ulittle32_t>(0);
275*349cc55cSDimitry Andric     m.TimeDateStamp = static_cast<llvm::support::ulittle32_t>(std::time(0));
276*349cc55cSDimitry Andric     m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>(
277*349cc55cSDimitry Andric         size_before + module_stream_size + helper_data.GetByteSize());
278*349cc55cSDimitry Andric     m.VersionInfo = info;
279*349cc55cSDimitry Andric     m.CvRecord = ld_cv;
280*349cc55cSDimitry Andric     m.MiscRecord = ld;
281*349cc55cSDimitry Andric 
282*349cc55cSDimitry Andric     error = WriteString(module_name, &helper_data);
283*349cc55cSDimitry Andric 
284*349cc55cSDimitry Andric     if (error.Fail())
285*349cc55cSDimitry Andric       return error;
286*349cc55cSDimitry Andric 
287*349cc55cSDimitry Andric     m_data.AppendData(&m, sizeof(llvm::minidump::Module));
288*349cc55cSDimitry Andric   }
289*349cc55cSDimitry Andric 
290*349cc55cSDimitry Andric   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
291*349cc55cSDimitry Andric   return error;
292*349cc55cSDimitry Andric }
293*349cc55cSDimitry Andric 
294*349cc55cSDimitry Andric uint16_t read_register_u16_raw(RegisterContext *reg_ctx,
295*349cc55cSDimitry Andric                                const std::string &reg_name) {
296*349cc55cSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
297*349cc55cSDimitry Andric   if (!reg_info)
298*349cc55cSDimitry Andric     return 0;
299*349cc55cSDimitry Andric   lldb_private::RegisterValue reg_value;
300*349cc55cSDimitry Andric   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
301*349cc55cSDimitry Andric   if (!success)
302*349cc55cSDimitry Andric     return 0;
303*349cc55cSDimitry Andric   return reg_value.GetAsUInt16();
304*349cc55cSDimitry Andric }
305*349cc55cSDimitry Andric 
306*349cc55cSDimitry Andric uint32_t read_register_u32_raw(RegisterContext *reg_ctx,
307*349cc55cSDimitry Andric                                const std::string &reg_name) {
308*349cc55cSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
309*349cc55cSDimitry Andric   if (!reg_info)
310*349cc55cSDimitry Andric     return 0;
311*349cc55cSDimitry Andric   lldb_private::RegisterValue reg_value;
312*349cc55cSDimitry Andric   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
313*349cc55cSDimitry Andric   if (!success)
314*349cc55cSDimitry Andric     return 0;
315*349cc55cSDimitry Andric   return reg_value.GetAsUInt32();
316*349cc55cSDimitry Andric }
317*349cc55cSDimitry Andric 
318*349cc55cSDimitry Andric uint64_t read_register_u64_raw(RegisterContext *reg_ctx,
319*349cc55cSDimitry Andric                                const std::string &reg_name) {
320*349cc55cSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
321*349cc55cSDimitry Andric   if (!reg_info)
322*349cc55cSDimitry Andric     return 0;
323*349cc55cSDimitry Andric   lldb_private::RegisterValue reg_value;
324*349cc55cSDimitry Andric   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
325*349cc55cSDimitry Andric   if (!success)
326*349cc55cSDimitry Andric     return 0;
327*349cc55cSDimitry Andric   return reg_value.GetAsUInt64();
328*349cc55cSDimitry Andric }
329*349cc55cSDimitry Andric 
330*349cc55cSDimitry Andric llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx,
331*349cc55cSDimitry Andric                                              const std::string &reg_name) {
332*349cc55cSDimitry Andric   return static_cast<llvm::support::ulittle16_t>(
333*349cc55cSDimitry Andric       read_register_u16_raw(reg_ctx, reg_name));
334*349cc55cSDimitry Andric }
335*349cc55cSDimitry Andric 
336*349cc55cSDimitry Andric llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx,
337*349cc55cSDimitry Andric                                              const std::string &reg_name) {
338*349cc55cSDimitry Andric   return static_cast<llvm::support::ulittle32_t>(
339*349cc55cSDimitry Andric       read_register_u32_raw(reg_ctx, reg_name));
340*349cc55cSDimitry Andric }
341*349cc55cSDimitry Andric 
342*349cc55cSDimitry Andric llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx,
343*349cc55cSDimitry Andric                                              const std::string &reg_name) {
344*349cc55cSDimitry Andric   return static_cast<llvm::support::ulittle64_t>(
345*349cc55cSDimitry Andric       read_register_u64_raw(reg_ctx, reg_name));
346*349cc55cSDimitry Andric }
347*349cc55cSDimitry Andric 
348*349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64
349*349cc55cSDimitry Andric GetThreadContext_64(RegisterContext *reg_ctx) {
350*349cc55cSDimitry Andric   lldb_private::minidump::MinidumpContext_x86_64 thread_context;
351*349cc55cSDimitry Andric   thread_context.context_flags = static_cast<uint32_t>(
352*349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag |
353*349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::Control |
354*349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::Segments |
355*349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::Integer);
356*349cc55cSDimitry Andric   thread_context.rax = read_register_u64(reg_ctx, "rax");
357*349cc55cSDimitry Andric   thread_context.rbx = read_register_u64(reg_ctx, "rbx");
358*349cc55cSDimitry Andric   thread_context.rcx = read_register_u64(reg_ctx, "rcx");
359*349cc55cSDimitry Andric   thread_context.rdx = read_register_u64(reg_ctx, "rdx");
360*349cc55cSDimitry Andric   thread_context.rdi = read_register_u64(reg_ctx, "rdi");
361*349cc55cSDimitry Andric   thread_context.rsi = read_register_u64(reg_ctx, "rsi");
362*349cc55cSDimitry Andric   thread_context.rbp = read_register_u64(reg_ctx, "rbp");
363*349cc55cSDimitry Andric   thread_context.rsp = read_register_u64(reg_ctx, "rsp");
364*349cc55cSDimitry Andric   thread_context.r8 = read_register_u64(reg_ctx, "r8");
365*349cc55cSDimitry Andric   thread_context.r9 = read_register_u64(reg_ctx, "r9");
366*349cc55cSDimitry Andric   thread_context.r10 = read_register_u64(reg_ctx, "r10");
367*349cc55cSDimitry Andric   thread_context.r11 = read_register_u64(reg_ctx, "r11");
368*349cc55cSDimitry Andric   thread_context.r12 = read_register_u64(reg_ctx, "r12");
369*349cc55cSDimitry Andric   thread_context.r13 = read_register_u64(reg_ctx, "r13");
370*349cc55cSDimitry Andric   thread_context.r14 = read_register_u64(reg_ctx, "r14");
371*349cc55cSDimitry Andric   thread_context.r15 = read_register_u64(reg_ctx, "r15");
372*349cc55cSDimitry Andric   thread_context.rip = read_register_u64(reg_ctx, "rip");
373*349cc55cSDimitry Andric   thread_context.eflags = read_register_u32(reg_ctx, "rflags");
374*349cc55cSDimitry Andric   thread_context.cs = read_register_u16(reg_ctx, "cs");
375*349cc55cSDimitry Andric   thread_context.fs = read_register_u16(reg_ctx, "fs");
376*349cc55cSDimitry Andric   thread_context.gs = read_register_u16(reg_ctx, "gs");
377*349cc55cSDimitry Andric   thread_context.ss = read_register_u16(reg_ctx, "ss");
378*349cc55cSDimitry Andric   thread_context.ds = read_register_u16(reg_ctx, "ds");
379*349cc55cSDimitry Andric   return thread_context;
380*349cc55cSDimitry Andric }
381*349cc55cSDimitry Andric 
382*349cc55cSDimitry Andric // Function returns start and size of the memory region that contains
383*349cc55cSDimitry Andric // memory location pointed to by the current stack pointer.
384*349cc55cSDimitry Andric llvm::Expected<std::pair<addr_t, addr_t>>
385*349cc55cSDimitry Andric findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) {
386*349cc55cSDimitry Andric   MemoryRegionInfo range_info;
387*349cc55cSDimitry Andric   Status error = process_sp->GetMemoryRegionInfo(rsp, range_info);
388*349cc55cSDimitry Andric   // Skip failed memory region requests or any regions with no permissions.
389*349cc55cSDimitry Andric   if (error.Fail() || range_info.GetLLDBPermissions() == 0)
390*349cc55cSDimitry Andric     return llvm::createStringError(
391*349cc55cSDimitry Andric         std::errc::not_supported,
392*349cc55cSDimitry Andric         "unable to load stack segment of the process");
393*349cc55cSDimitry Andric 
394*349cc55cSDimitry Andric   const addr_t addr = range_info.GetRange().GetRangeBase();
395*349cc55cSDimitry Andric   const addr_t size = range_info.GetRange().GetByteSize();
396*349cc55cSDimitry Andric 
397*349cc55cSDimitry Andric   if (size == 0)
398*349cc55cSDimitry Andric     return llvm::createStringError(std::errc::not_supported,
399*349cc55cSDimitry Andric                                    "stack segment of the process is empty");
400*349cc55cSDimitry Andric 
401*349cc55cSDimitry Andric   return std::make_pair(addr, size);
402*349cc55cSDimitry Andric }
403*349cc55cSDimitry Andric 
404*349cc55cSDimitry Andric Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) {
405*349cc55cSDimitry Andric   constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread);
406*349cc55cSDimitry Andric   lldb_private::ThreadList thread_list = process_sp->GetThreadList();
407*349cc55cSDimitry Andric 
408*349cc55cSDimitry Andric   // size of the entire thread stream consists of:
409*349cc55cSDimitry Andric   // number of threads and threads array
410*349cc55cSDimitry Andric   size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) +
411*349cc55cSDimitry Andric                               thread_list.GetSize() * minidump_thread_size;
412*349cc55cSDimitry Andric   // save for the ability to set up RVA
413*349cc55cSDimitry Andric   size_t size_before = GetCurrentDataEndOffset();
414*349cc55cSDimitry Andric 
415*349cc55cSDimitry Andric   AddDirectory(StreamType::ThreadList, thread_stream_size);
416*349cc55cSDimitry Andric 
417*349cc55cSDimitry Andric   llvm::support::ulittle32_t thread_count =
418*349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(thread_list.GetSize());
419*349cc55cSDimitry Andric   m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t));
420*349cc55cSDimitry Andric 
421*349cc55cSDimitry Andric   DataBufferHeap helper_data;
422*349cc55cSDimitry Andric 
423*349cc55cSDimitry Andric   const uint32_t num_threads = thread_list.GetSize();
424*349cc55cSDimitry Andric 
425*349cc55cSDimitry Andric   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
426*349cc55cSDimitry Andric     ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
427*349cc55cSDimitry Andric     RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
428*349cc55cSDimitry Andric     Status error;
429*349cc55cSDimitry Andric 
430*349cc55cSDimitry Andric     if (!reg_ctx_sp) {
431*349cc55cSDimitry Andric       error.SetErrorString("Unable to get the register context.");
432*349cc55cSDimitry Andric       return error;
433*349cc55cSDimitry Andric     }
434*349cc55cSDimitry Andric     RegisterContext *reg_ctx = reg_ctx_sp.get();
435*349cc55cSDimitry Andric     auto thread_context = GetThreadContext_64(reg_ctx);
436*349cc55cSDimitry Andric     uint64_t rsp = read_register_u64_raw(reg_ctx, "rsp");
437*349cc55cSDimitry Andric     auto expected_address_range = findStackHelper(process_sp, rsp);
438*349cc55cSDimitry Andric 
439*349cc55cSDimitry Andric     if (!expected_address_range) {
440*349cc55cSDimitry Andric       error.SetErrorString("Unable to get the stack address.");
441*349cc55cSDimitry Andric       return error;
442*349cc55cSDimitry Andric     }
443*349cc55cSDimitry Andric 
444*349cc55cSDimitry Andric     std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range);
445*349cc55cSDimitry Andric     uint64_t addr = range.first;
446*349cc55cSDimitry Andric     uint64_t size = range.second;
447*349cc55cSDimitry Andric 
448*349cc55cSDimitry Andric     auto data_up = std::make_unique<DataBufferHeap>(size, 0);
449*349cc55cSDimitry Andric     const size_t stack_bytes_read =
450*349cc55cSDimitry Andric         process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
451*349cc55cSDimitry Andric 
452*349cc55cSDimitry Andric     if (error.Fail())
453*349cc55cSDimitry Andric       return error;
454*349cc55cSDimitry Andric 
455*349cc55cSDimitry Andric     LocationDescriptor stack_memory;
456*349cc55cSDimitry Andric     stack_memory.DataSize =
457*349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(stack_bytes_read);
458*349cc55cSDimitry Andric     stack_memory.RVA = static_cast<llvm::support::ulittle32_t>(
459*349cc55cSDimitry Andric         size_before + thread_stream_size + helper_data.GetByteSize());
460*349cc55cSDimitry Andric 
461*349cc55cSDimitry Andric     MemoryDescriptor stack;
462*349cc55cSDimitry Andric     stack.StartOfMemoryRange = static_cast<llvm::support::ulittle64_t>(addr);
463*349cc55cSDimitry Andric     stack.Memory = stack_memory;
464*349cc55cSDimitry Andric 
465*349cc55cSDimitry Andric     helper_data.AppendData(data_up->GetBytes(), stack_bytes_read);
466*349cc55cSDimitry Andric 
467*349cc55cSDimitry Andric     LocationDescriptor thread_context_memory_locator;
468*349cc55cSDimitry Andric     thread_context_memory_locator.DataSize =
469*349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(sizeof(thread_context));
470*349cc55cSDimitry Andric     thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(
471*349cc55cSDimitry Andric         size_before + thread_stream_size + helper_data.GetByteSize());
472*349cc55cSDimitry Andric 
473*349cc55cSDimitry Andric     helper_data.AppendData(
474*349cc55cSDimitry Andric         &thread_context,
475*349cc55cSDimitry Andric         sizeof(lldb_private::minidump::MinidumpContext_x86_64));
476*349cc55cSDimitry Andric 
477*349cc55cSDimitry Andric     llvm::minidump::Thread t;
478*349cc55cSDimitry Andric     t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
479*349cc55cSDimitry Andric     t.SuspendCount = static_cast<llvm::support::ulittle32_t>(
480*349cc55cSDimitry Andric         (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0);
481*349cc55cSDimitry Andric     t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0);
482*349cc55cSDimitry Andric     t.Priority = static_cast<llvm::support::ulittle32_t>(0);
483*349cc55cSDimitry Andric     t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0);
484*349cc55cSDimitry Andric     t.Stack = stack, t.Context = thread_context_memory_locator;
485*349cc55cSDimitry Andric 
486*349cc55cSDimitry Andric     m_data.AppendData(&t, sizeof(llvm::minidump::Thread));
487*349cc55cSDimitry Andric   }
488*349cc55cSDimitry Andric 
489*349cc55cSDimitry Andric   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
490*349cc55cSDimitry Andric   return Status();
491*349cc55cSDimitry Andric }
492*349cc55cSDimitry Andric 
493*349cc55cSDimitry Andric Status MinidumpFileBuilder::AddException(const lldb::ProcessSP &process_sp) {
494*349cc55cSDimitry Andric   Status error;
495*349cc55cSDimitry Andric   lldb_private::ThreadList thread_list = process_sp->GetThreadList();
496*349cc55cSDimitry Andric 
497*349cc55cSDimitry Andric   const uint32_t num_threads = thread_list.GetSize();
498*349cc55cSDimitry Andric   uint32_t stop_reason_thread_idx = 0;
499*349cc55cSDimitry Andric   for (stop_reason_thread_idx = 0; stop_reason_thread_idx < num_threads;
500*349cc55cSDimitry Andric        ++stop_reason_thread_idx) {
501*349cc55cSDimitry Andric     ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx));
502*349cc55cSDimitry Andric     StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
503*349cc55cSDimitry Andric 
504*349cc55cSDimitry Andric     if (stop_info_sp && stop_info_sp->IsValid())
505*349cc55cSDimitry Andric       break;
506*349cc55cSDimitry Andric   }
507*349cc55cSDimitry Andric 
508*349cc55cSDimitry Andric   if (stop_reason_thread_idx == num_threads) {
509*349cc55cSDimitry Andric     error.SetErrorString("No stop reason thread found.");
510*349cc55cSDimitry Andric     return error;
511*349cc55cSDimitry Andric   }
512*349cc55cSDimitry Andric 
513*349cc55cSDimitry Andric   constexpr size_t minidump_exception_size =
514*349cc55cSDimitry Andric       sizeof(llvm::minidump::ExceptionStream);
515*349cc55cSDimitry Andric   AddDirectory(StreamType::Exception, minidump_exception_size);
516*349cc55cSDimitry Andric   size_t size_before = GetCurrentDataEndOffset();
517*349cc55cSDimitry Andric 
518*349cc55cSDimitry Andric   ThreadSP thread_sp(thread_list.GetThreadAtIndex(stop_reason_thread_idx));
519*349cc55cSDimitry Andric   RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
520*349cc55cSDimitry Andric   RegisterContext *reg_ctx = reg_ctx_sp.get();
521*349cc55cSDimitry Andric   auto thread_context = GetThreadContext_64(reg_ctx);
522*349cc55cSDimitry Andric   StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
523*349cc55cSDimitry Andric 
524*349cc55cSDimitry Andric   DataBufferHeap helper_data;
525*349cc55cSDimitry Andric 
526*349cc55cSDimitry Andric   LocationDescriptor thread_context_memory_locator;
527*349cc55cSDimitry Andric   thread_context_memory_locator.DataSize =
528*349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(sizeof(thread_context));
529*349cc55cSDimitry Andric   thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(
530*349cc55cSDimitry Andric       size_before + minidump_exception_size + helper_data.GetByteSize());
531*349cc55cSDimitry Andric 
532*349cc55cSDimitry Andric   helper_data.AppendData(
533*349cc55cSDimitry Andric       &thread_context, sizeof(lldb_private::minidump::MinidumpContext_x86_64));
534*349cc55cSDimitry Andric 
535*349cc55cSDimitry Andric   Exception exp_record;
536*349cc55cSDimitry Andric   exp_record.ExceptionCode =
537*349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());
538*349cc55cSDimitry Andric   exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0);
539*349cc55cSDimitry Andric   exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0);
540*349cc55cSDimitry Andric   exp_record.ExceptionAddress = read_register_u64(reg_ctx, "rip");
541*349cc55cSDimitry Andric   exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0);
542*349cc55cSDimitry Andric   exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
543*349cc55cSDimitry Andric   // exp_record.ExceptionInformation;
544*349cc55cSDimitry Andric 
545*349cc55cSDimitry Andric   ExceptionStream exp_stream;
546*349cc55cSDimitry Andric   exp_stream.ThreadId =
547*349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
548*349cc55cSDimitry Andric   exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
549*349cc55cSDimitry Andric   exp_stream.ExceptionRecord = exp_record;
550*349cc55cSDimitry Andric   exp_stream.ThreadContext = thread_context_memory_locator;
551*349cc55cSDimitry Andric 
552*349cc55cSDimitry Andric   m_data.AppendData(&exp_stream, minidump_exception_size);
553*349cc55cSDimitry Andric   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
554*349cc55cSDimitry Andric   return error;
555*349cc55cSDimitry Andric }
556*349cc55cSDimitry Andric 
557*349cc55cSDimitry Andric lldb_private::Status
558*349cc55cSDimitry Andric MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp) {
559*349cc55cSDimitry Andric   Status error;
560*349cc55cSDimitry Andric 
561*349cc55cSDimitry Andric   if (error.Fail()) {
562*349cc55cSDimitry Andric     error.SetErrorString("Process doesn't support getting memory region info.");
563*349cc55cSDimitry Andric     return error;
564*349cc55cSDimitry Andric   }
565*349cc55cSDimitry Andric 
566*349cc55cSDimitry Andric   // Get interesting addresses
567*349cc55cSDimitry Andric   std::vector<size_t> interesting_addresses;
568*349cc55cSDimitry Andric   auto thread_list = process_sp->GetThreadList();
569*349cc55cSDimitry Andric   for (size_t i = 0; i < thread_list.GetSize(); ++i) {
570*349cc55cSDimitry Andric     ThreadSP thread_sp(thread_list.GetThreadAtIndex(i));
571*349cc55cSDimitry Andric     RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
572*349cc55cSDimitry Andric     RegisterContext *reg_ctx = reg_ctx_sp.get();
573*349cc55cSDimitry Andric 
574*349cc55cSDimitry Andric     interesting_addresses.push_back(read_register_u64(reg_ctx, "rsp"));
575*349cc55cSDimitry Andric     interesting_addresses.push_back(read_register_u64(reg_ctx, "rip"));
576*349cc55cSDimitry Andric   }
577*349cc55cSDimitry Andric 
578*349cc55cSDimitry Andric   DataBufferHeap helper_data;
579*349cc55cSDimitry Andric   std::vector<MemoryDescriptor> mem_descriptors;
580*349cc55cSDimitry Andric 
581*349cc55cSDimitry Andric   std::set<addr_t> visited_region_base_addresses;
582*349cc55cSDimitry Andric   for (size_t interesting_address : interesting_addresses) {
583*349cc55cSDimitry Andric     MemoryRegionInfo range_info;
584*349cc55cSDimitry Andric     error = process_sp->GetMemoryRegionInfo(interesting_address, range_info);
585*349cc55cSDimitry Andric     // Skip failed memory region requests or any regions with no permissions.
586*349cc55cSDimitry Andric     if (error.Fail() || range_info.GetLLDBPermissions() == 0)
587*349cc55cSDimitry Andric       continue;
588*349cc55cSDimitry Andric     const addr_t addr = range_info.GetRange().GetRangeBase();
589*349cc55cSDimitry Andric     // Skip any regions we have already saved out.
590*349cc55cSDimitry Andric     if (visited_region_base_addresses.insert(addr).second == false)
591*349cc55cSDimitry Andric       continue;
592*349cc55cSDimitry Andric     const addr_t size = range_info.GetRange().GetByteSize();
593*349cc55cSDimitry Andric     if (size == 0)
594*349cc55cSDimitry Andric       continue;
595*349cc55cSDimitry Andric     auto data_up = std::make_unique<DataBufferHeap>(size, 0);
596*349cc55cSDimitry Andric     const size_t bytes_read =
597*349cc55cSDimitry Andric         process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
598*349cc55cSDimitry Andric     if (bytes_read == 0)
599*349cc55cSDimitry Andric       continue;
600*349cc55cSDimitry Andric     // We have a good memory region with valid bytes to store.
601*349cc55cSDimitry Andric     LocationDescriptor memory_dump;
602*349cc55cSDimitry Andric     memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(bytes_read);
603*349cc55cSDimitry Andric     memory_dump.RVA =
604*349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
605*349cc55cSDimitry Andric     MemoryDescriptor memory_desc;
606*349cc55cSDimitry Andric     memory_desc.StartOfMemoryRange =
607*349cc55cSDimitry Andric         static_cast<llvm::support::ulittle64_t>(addr);
608*349cc55cSDimitry Andric     memory_desc.Memory = memory_dump;
609*349cc55cSDimitry Andric     mem_descriptors.push_back(memory_desc);
610*349cc55cSDimitry Andric     m_data.AppendData(data_up->GetBytes(), bytes_read);
611*349cc55cSDimitry Andric   }
612*349cc55cSDimitry Andric 
613*349cc55cSDimitry Andric   AddDirectory(StreamType::MemoryList,
614*349cc55cSDimitry Andric                sizeof(llvm::support::ulittle32_t) +
615*349cc55cSDimitry Andric                    mem_descriptors.size() *
616*349cc55cSDimitry Andric                        sizeof(llvm::minidump::MemoryDescriptor));
617*349cc55cSDimitry Andric   llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size());
618*349cc55cSDimitry Andric 
619*349cc55cSDimitry Andric   m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t));
620*349cc55cSDimitry Andric   for (auto memory_descriptor : mem_descriptors) {
621*349cc55cSDimitry Andric     m_data.AppendData(&memory_descriptor,
622*349cc55cSDimitry Andric                       sizeof(llvm::minidump::MemoryDescriptor));
623*349cc55cSDimitry Andric   }
624*349cc55cSDimitry Andric 
625*349cc55cSDimitry Andric   return error;
626*349cc55cSDimitry Andric }
627*349cc55cSDimitry Andric 
628*349cc55cSDimitry Andric void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) {
629*349cc55cSDimitry Andric   AddDirectory(StreamType::MiscInfo,
630*349cc55cSDimitry Andric                sizeof(lldb_private::minidump::MinidumpMiscInfo));
631*349cc55cSDimitry Andric 
632*349cc55cSDimitry Andric   lldb_private::minidump::MinidumpMiscInfo misc_info;
633*349cc55cSDimitry Andric   misc_info.size = static_cast<llvm::support::ulittle32_t>(
634*349cc55cSDimitry Andric       sizeof(lldb_private::minidump::MinidumpMiscInfo));
635*349cc55cSDimitry Andric   // Default set flags1 to 0, in case that we will not be able to
636*349cc55cSDimitry Andric   // get any information
637*349cc55cSDimitry Andric   misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0);
638*349cc55cSDimitry Andric 
639*349cc55cSDimitry Andric   lldb_private::ProcessInstanceInfo process_info;
640*349cc55cSDimitry Andric   process_sp->GetProcessInfo(process_info);
641*349cc55cSDimitry Andric   if (process_info.ProcessIDIsValid()) {
642*349cc55cSDimitry Andric     // Set flags1 to reflect that PID is filled in
643*349cc55cSDimitry Andric     misc_info.flags1 =
644*349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>(
645*349cc55cSDimitry Andric             lldb_private::minidump::MinidumpMiscInfoFlags::ProcessID));
646*349cc55cSDimitry Andric     misc_info.process_id =
647*349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID());
648*349cc55cSDimitry Andric   }
649*349cc55cSDimitry Andric 
650*349cc55cSDimitry Andric   m_data.AppendData(&misc_info,
651*349cc55cSDimitry Andric                     sizeof(lldb_private::minidump::MinidumpMiscInfo));
652*349cc55cSDimitry Andric }
653*349cc55cSDimitry Andric 
654*349cc55cSDimitry Andric std::unique_ptr<llvm::MemoryBuffer>
655*349cc55cSDimitry Andric getFileStreamHelper(const std::string &path) {
656*349cc55cSDimitry Andric   auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path);
657*349cc55cSDimitry Andric   if (!maybe_stream)
658*349cc55cSDimitry Andric     return nullptr;
659*349cc55cSDimitry Andric   return std::move(maybe_stream.get());
660*349cc55cSDimitry Andric }
661*349cc55cSDimitry Andric 
662*349cc55cSDimitry Andric void MinidumpFileBuilder::AddLinuxFileStreams(
663*349cc55cSDimitry Andric     const lldb::ProcessSP &process_sp) {
664*349cc55cSDimitry Andric   std::vector<std::pair<StreamType, std::string>> files_with_stream_types = {
665*349cc55cSDimitry Andric       {StreamType::LinuxCPUInfo, "/proc/cpuinfo"},
666*349cc55cSDimitry Andric       {StreamType::LinuxLSBRelease, "/etc/lsb-release"},
667*349cc55cSDimitry Andric   };
668*349cc55cSDimitry Andric 
669*349cc55cSDimitry Andric   lldb_private::ProcessInstanceInfo process_info;
670*349cc55cSDimitry Andric   process_sp->GetProcessInfo(process_info);
671*349cc55cSDimitry Andric   if (process_info.ProcessIDIsValid()) {
672*349cc55cSDimitry Andric     lldb::pid_t pid = process_info.GetProcessID();
673*349cc55cSDimitry Andric     std::string pid_str = std::to_string(pid);
674*349cc55cSDimitry Andric     files_with_stream_types.push_back(
675*349cc55cSDimitry Andric         {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"});
676*349cc55cSDimitry Andric     files_with_stream_types.push_back(
677*349cc55cSDimitry Andric         {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"});
678*349cc55cSDimitry Andric     files_with_stream_types.push_back(
679*349cc55cSDimitry Andric         {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"});
680*349cc55cSDimitry Andric     files_with_stream_types.push_back(
681*349cc55cSDimitry Andric         {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"});
682*349cc55cSDimitry Andric     files_with_stream_types.push_back(
683*349cc55cSDimitry Andric         {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"});
684*349cc55cSDimitry Andric     files_with_stream_types.push_back(
685*349cc55cSDimitry Andric         {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"});
686*349cc55cSDimitry Andric     files_with_stream_types.push_back(
687*349cc55cSDimitry Andric         {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"});
688*349cc55cSDimitry Andric   }
689*349cc55cSDimitry Andric 
690*349cc55cSDimitry Andric   for (const auto &entry : files_with_stream_types) {
691*349cc55cSDimitry Andric     StreamType stream = entry.first;
692*349cc55cSDimitry Andric     std::string path = entry.second;
693*349cc55cSDimitry Andric     auto memory_buffer = getFileStreamHelper(path);
694*349cc55cSDimitry Andric 
695*349cc55cSDimitry Andric     if (memory_buffer) {
696*349cc55cSDimitry Andric       size_t size = memory_buffer->getBufferSize();
697*349cc55cSDimitry Andric       if (size == 0)
698*349cc55cSDimitry Andric         continue;
699*349cc55cSDimitry Andric       AddDirectory(stream, size);
700*349cc55cSDimitry Andric       m_data.AppendData(memory_buffer->getBufferStart(), size);
701*349cc55cSDimitry Andric     }
702*349cc55cSDimitry Andric   }
703*349cc55cSDimitry Andric }
704*349cc55cSDimitry Andric 
705*349cc55cSDimitry Andric Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const {
706*349cc55cSDimitry Andric   constexpr size_t header_size = sizeof(llvm::minidump::Header);
707*349cc55cSDimitry Andric   constexpr size_t directory_size = sizeof(llvm::minidump::Directory);
708*349cc55cSDimitry Andric 
709*349cc55cSDimitry Andric   // write header
710*349cc55cSDimitry Andric   llvm::minidump::Header header;
711*349cc55cSDimitry Andric   header.Signature = static_cast<llvm::support::ulittle32_t>(
712*349cc55cSDimitry Andric       llvm::minidump::Header::MagicSignature);
713*349cc55cSDimitry Andric   header.Version = static_cast<llvm::support::ulittle32_t>(
714*349cc55cSDimitry Andric       llvm::minidump::Header::MagicVersion);
715*349cc55cSDimitry Andric   header.NumberOfStreams =
716*349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(GetDirectoriesNum());
717*349cc55cSDimitry Andric   header.StreamDirectoryRVA =
718*349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
719*349cc55cSDimitry Andric   header.Checksum = static_cast<llvm::support::ulittle32_t>(
720*349cc55cSDimitry Andric       0u), // not used in most of the writers
721*349cc55cSDimitry Andric       header.TimeDateStamp =
722*349cc55cSDimitry Andric           static_cast<llvm::support::ulittle32_t>(std::time(0));
723*349cc55cSDimitry Andric   header.Flags =
724*349cc55cSDimitry Andric       static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag
725*349cc55cSDimitry Andric 
726*349cc55cSDimitry Andric   Status error;
727*349cc55cSDimitry Andric   size_t bytes_written;
728*349cc55cSDimitry Andric 
729*349cc55cSDimitry Andric   bytes_written = header_size;
730*349cc55cSDimitry Andric   error = core_file->Write(&header, bytes_written);
731*349cc55cSDimitry Andric   if (error.Fail() || bytes_written != header_size) {
732*349cc55cSDimitry Andric     if (bytes_written != header_size)
733*349cc55cSDimitry Andric       error.SetErrorStringWithFormat(
734*349cc55cSDimitry Andric           "unable to write the header (written %zd/%zd)", bytes_written,
735*349cc55cSDimitry Andric           header_size);
736*349cc55cSDimitry Andric     return error;
737*349cc55cSDimitry Andric   }
738*349cc55cSDimitry Andric 
739*349cc55cSDimitry Andric   // write data
740*349cc55cSDimitry Andric   bytes_written = m_data.GetByteSize();
741*349cc55cSDimitry Andric   error = core_file->Write(m_data.GetBytes(), bytes_written);
742*349cc55cSDimitry Andric   if (error.Fail() || bytes_written != m_data.GetByteSize()) {
743*349cc55cSDimitry Andric     if (bytes_written != m_data.GetByteSize())
744*349cc55cSDimitry Andric       error.SetErrorStringWithFormat(
745*349cc55cSDimitry Andric           "unable to write the data (written %zd/%" PRIu64 ")", bytes_written,
746*349cc55cSDimitry Andric           m_data.GetByteSize());
747*349cc55cSDimitry Andric     return error;
748*349cc55cSDimitry Andric   }
749*349cc55cSDimitry Andric 
750*349cc55cSDimitry Andric   // write directories
751*349cc55cSDimitry Andric   for (const Directory &dir : m_directories) {
752*349cc55cSDimitry Andric     bytes_written = directory_size;
753*349cc55cSDimitry Andric     error = core_file->Write(&dir, bytes_written);
754*349cc55cSDimitry Andric     if (error.Fail() || bytes_written != directory_size) {
755*349cc55cSDimitry Andric       if (bytes_written != directory_size)
756*349cc55cSDimitry Andric         error.SetErrorStringWithFormat(
757*349cc55cSDimitry Andric             "unable to write the directory (written %zd/%zd)", bytes_written,
758*349cc55cSDimitry Andric             directory_size);
759*349cc55cSDimitry Andric       return error;
760*349cc55cSDimitry Andric     }
761*349cc55cSDimitry Andric   }
762*349cc55cSDimitry Andric 
763*349cc55cSDimitry Andric   return error;
764*349cc55cSDimitry Andric }
765*349cc55cSDimitry Andric 
766*349cc55cSDimitry Andric size_t MinidumpFileBuilder::GetDirectoriesNum() const {
767*349cc55cSDimitry Andric   return m_directories.size();
768*349cc55cSDimitry Andric }
769*349cc55cSDimitry Andric 
770*349cc55cSDimitry Andric size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const {
771*349cc55cSDimitry Andric   return sizeof(llvm::minidump::Header) + m_data.GetByteSize();
772*349cc55cSDimitry Andric }
773