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