xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1349cc55cSDimitry Andric //===-- MinidumpFileBuilder.cpp -------------------------------------------===//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric 
9349cc55cSDimitry Andric #include "MinidumpFileBuilder.h"
10349cc55cSDimitry Andric 
115f757f3fSDimitry Andric #include "Plugins/Process/minidump/RegisterContextMinidump_ARM64.h"
12349cc55cSDimitry Andric #include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
13349cc55cSDimitry Andric 
14349cc55cSDimitry Andric #include "lldb/Core/Module.h"
15349cc55cSDimitry Andric #include "lldb/Core/ModuleList.h"
16349cc55cSDimitry Andric #include "lldb/Core/Section.h"
17*0fca6ea1SDimitry Andric #include "lldb/Target/ABI.h"
18349cc55cSDimitry Andric #include "lldb/Target/MemoryRegionInfo.h"
19349cc55cSDimitry Andric #include "lldb/Target/Process.h"
20349cc55cSDimitry Andric #include "lldb/Target/RegisterContext.h"
21349cc55cSDimitry Andric #include "lldb/Target/StopInfo.h"
22349cc55cSDimitry Andric #include "lldb/Target/ThreadList.h"
23*0fca6ea1SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
24349cc55cSDimitry Andric #include "lldb/Utility/DataExtractor.h"
25*0fca6ea1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
26*0fca6ea1SDimitry Andric #include "lldb/Utility/Log.h"
27*0fca6ea1SDimitry Andric #include "lldb/Utility/RangeMap.h"
28349cc55cSDimitry Andric #include "lldb/Utility/RegisterValue.h"
29349cc55cSDimitry Andric 
30349cc55cSDimitry Andric #include "llvm/ADT/StringRef.h"
31349cc55cSDimitry Andric #include "llvm/BinaryFormat/Minidump.h"
32349cc55cSDimitry Andric #include "llvm/Support/ConvertUTF.h"
33*0fca6ea1SDimitry Andric #include "llvm/Support/Endian.h"
34349cc55cSDimitry Andric #include "llvm/Support/Error.h"
35*0fca6ea1SDimitry Andric #include "llvm/TargetParser/Triple.h"
36349cc55cSDimitry Andric 
37349cc55cSDimitry Andric #include "Plugins/Process/minidump/MinidumpTypes.h"
38*0fca6ea1SDimitry Andric #include "lldb/lldb-enumerations.h"
39*0fca6ea1SDimitry Andric #include "lldb/lldb-forward.h"
40*0fca6ea1SDimitry Andric #include "lldb/lldb-types.h"
41349cc55cSDimitry Andric 
42*0fca6ea1SDimitry Andric #include <algorithm>
43349cc55cSDimitry Andric #include <cinttypes>
44*0fca6ea1SDimitry Andric #include <climits>
45*0fca6ea1SDimitry Andric #include <cstddef>
46*0fca6ea1SDimitry Andric #include <cstdint>
47*0fca6ea1SDimitry Andric #include <functional>
48*0fca6ea1SDimitry Andric #include <iostream>
49*0fca6ea1SDimitry Andric #include <set>
50*0fca6ea1SDimitry Andric #include <utility>
51*0fca6ea1SDimitry Andric #include <vector>
52349cc55cSDimitry Andric 
53349cc55cSDimitry Andric using namespace lldb;
54349cc55cSDimitry Andric using namespace lldb_private;
55349cc55cSDimitry Andric using namespace llvm::minidump;
56349cc55cSDimitry Andric 
57*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddHeaderAndCalculateDirectories() {
58*0fca6ea1SDimitry Andric   // First set the offset on the file, and on the bytes saved
59*0fca6ea1SDimitry Andric   m_saved_data_size = HEADER_SIZE;
60*0fca6ea1SDimitry Andric   // We know we will have at least Misc, SystemInfo, Modules, and ThreadList
61*0fca6ea1SDimitry Andric   // (corresponding memory list for stacks) And an additional memory list for
62*0fca6ea1SDimitry Andric   // non-stacks.
63*0fca6ea1SDimitry Andric   lldb_private::Target &target = m_process_sp->GetTarget();
64*0fca6ea1SDimitry Andric   m_expected_directories = 6;
65*0fca6ea1SDimitry Andric   // Check if OS is linux and reserve directory space for all linux specific
66*0fca6ea1SDimitry Andric   // breakpad extension directories.
67*0fca6ea1SDimitry Andric   if (target.GetArchitecture().GetTriple().getOS() ==
68*0fca6ea1SDimitry Andric       llvm::Triple::OSType::Linux)
69*0fca6ea1SDimitry Andric     m_expected_directories += 9;
70*0fca6ea1SDimitry Andric 
71*0fca6ea1SDimitry Andric   // Go through all of the threads and check for exceptions.
72*0fca6ea1SDimitry Andric   lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
73*0fca6ea1SDimitry Andric   const uint32_t num_threads = thread_list.GetSize();
74*0fca6ea1SDimitry Andric   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
75*0fca6ea1SDimitry Andric     ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
76*0fca6ea1SDimitry Andric     StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
77*0fca6ea1SDimitry Andric     if (stop_info_sp) {
78*0fca6ea1SDimitry Andric       const StopReason &stop_reason = stop_info_sp->GetStopReason();
79*0fca6ea1SDimitry Andric       if (stop_reason == StopReason::eStopReasonException ||
80*0fca6ea1SDimitry Andric           stop_reason == StopReason::eStopReasonSignal)
81*0fca6ea1SDimitry Andric         m_expected_directories++;
82*0fca6ea1SDimitry Andric     }
83*0fca6ea1SDimitry Andric   }
84*0fca6ea1SDimitry Andric 
85*0fca6ea1SDimitry Andric   m_saved_data_size +=
86*0fca6ea1SDimitry Andric       m_expected_directories * sizeof(llvm::minidump::Directory);
87*0fca6ea1SDimitry Andric   Status error;
88*0fca6ea1SDimitry Andric   offset_t new_offset = m_core_file->SeekFromStart(m_saved_data_size);
89*0fca6ea1SDimitry Andric   if (new_offset != m_saved_data_size)
90*0fca6ea1SDimitry Andric     error.SetErrorStringWithFormat("Failed to fill in header and directory "
91*0fca6ea1SDimitry Andric                                    "sections. Written / Expected (%" PRIx64
92*0fca6ea1SDimitry Andric                                    " / %" PRIx64 ")",
93*0fca6ea1SDimitry Andric                                    new_offset, m_saved_data_size);
94*0fca6ea1SDimitry Andric 
95*0fca6ea1SDimitry Andric   return error;
96*0fca6ea1SDimitry Andric }
97*0fca6ea1SDimitry Andric 
98*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddDirectory(StreamType type,
99*0fca6ea1SDimitry Andric                                          uint64_t stream_size) {
100*0fca6ea1SDimitry Andric   // We explicitly cast type, an 32b enum, to uint32_t to avoid warnings.
101*0fca6ea1SDimitry Andric   Status error;
102*0fca6ea1SDimitry Andric   if (GetCurrentDataEndOffset() > UINT32_MAX) {
103*0fca6ea1SDimitry Andric     error.SetErrorStringWithFormat("Unable to add directory for stream type "
104*0fca6ea1SDimitry Andric                                    "%x, offset is greater then 32 bit limit.",
105*0fca6ea1SDimitry Andric                                    (uint32_t)type);
106*0fca6ea1SDimitry Andric     return error;
107*0fca6ea1SDimitry Andric   }
108*0fca6ea1SDimitry Andric 
109*0fca6ea1SDimitry Andric   if (m_directories.size() + 1 > m_expected_directories) {
110*0fca6ea1SDimitry Andric     error.SetErrorStringWithFormat(
111*0fca6ea1SDimitry Andric         "Unable to add directory for stream type %x, exceeded expected number "
112*0fca6ea1SDimitry Andric         "of directories %zu.",
113*0fca6ea1SDimitry Andric         (uint32_t)type, m_expected_directories);
114*0fca6ea1SDimitry Andric     return error;
115*0fca6ea1SDimitry Andric   }
116*0fca6ea1SDimitry Andric 
117349cc55cSDimitry Andric   LocationDescriptor loc;
118349cc55cSDimitry Andric   loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size);
119349cc55cSDimitry Andric   // Stream will begin at the current end of data section
120349cc55cSDimitry Andric   loc.RVA = static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset());
121349cc55cSDimitry Andric 
122349cc55cSDimitry Andric   Directory dir;
123349cc55cSDimitry Andric   dir.Type = static_cast<llvm::support::little_t<StreamType>>(type);
124349cc55cSDimitry Andric   dir.Location = loc;
125349cc55cSDimitry Andric 
126349cc55cSDimitry Andric   m_directories.push_back(dir);
127*0fca6ea1SDimitry Andric   return error;
128349cc55cSDimitry Andric }
129349cc55cSDimitry Andric 
130*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddSystemInfo() {
131349cc55cSDimitry Andric   Status error;
132*0fca6ea1SDimitry Andric   const llvm::Triple &target_triple =
133*0fca6ea1SDimitry Andric       m_process_sp->GetTarget().GetArchitecture().GetTriple();
134*0fca6ea1SDimitry Andric   error =
135349cc55cSDimitry Andric       AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo));
136*0fca6ea1SDimitry Andric   if (error.Fail())
137*0fca6ea1SDimitry Andric     return error;
138349cc55cSDimitry Andric 
139349cc55cSDimitry Andric   llvm::minidump::ProcessorArchitecture arch;
140349cc55cSDimitry Andric   switch (target_triple.getArch()) {
141349cc55cSDimitry Andric   case llvm::Triple::ArchType::x86_64:
142349cc55cSDimitry Andric     arch = ProcessorArchitecture::AMD64;
143349cc55cSDimitry Andric     break;
144349cc55cSDimitry Andric   case llvm::Triple::ArchType::x86:
145349cc55cSDimitry Andric     arch = ProcessorArchitecture::X86;
146349cc55cSDimitry Andric     break;
147349cc55cSDimitry Andric   case llvm::Triple::ArchType::arm:
148349cc55cSDimitry Andric     arch = ProcessorArchitecture::ARM;
149349cc55cSDimitry Andric     break;
150349cc55cSDimitry Andric   case llvm::Triple::ArchType::aarch64:
151349cc55cSDimitry Andric     arch = ProcessorArchitecture::ARM64;
152349cc55cSDimitry Andric     break;
153349cc55cSDimitry Andric   case llvm::Triple::ArchType::mips64:
154349cc55cSDimitry Andric   case llvm::Triple::ArchType::mips64el:
155349cc55cSDimitry Andric   case llvm::Triple::ArchType::mips:
156349cc55cSDimitry Andric   case llvm::Triple::ArchType::mipsel:
157349cc55cSDimitry Andric     arch = ProcessorArchitecture::MIPS;
158349cc55cSDimitry Andric     break;
159349cc55cSDimitry Andric   case llvm::Triple::ArchType::ppc64:
160349cc55cSDimitry Andric   case llvm::Triple::ArchType::ppc:
161349cc55cSDimitry Andric   case llvm::Triple::ArchType::ppc64le:
162349cc55cSDimitry Andric     arch = ProcessorArchitecture::PPC;
163349cc55cSDimitry Andric     break;
164349cc55cSDimitry Andric   default:
165349cc55cSDimitry Andric     error.SetErrorStringWithFormat("Architecture %s not supported.",
166349cc55cSDimitry Andric                                    target_triple.getArchName().str().c_str());
167349cc55cSDimitry Andric     return error;
168349cc55cSDimitry Andric   };
169349cc55cSDimitry Andric 
170349cc55cSDimitry Andric   llvm::support::little_t<OSPlatform> platform_id;
171349cc55cSDimitry Andric   switch (target_triple.getOS()) {
172349cc55cSDimitry Andric   case llvm::Triple::OSType::Linux:
173349cc55cSDimitry Andric     if (target_triple.getEnvironment() ==
174349cc55cSDimitry Andric         llvm::Triple::EnvironmentType::Android)
175349cc55cSDimitry Andric       platform_id = OSPlatform::Android;
176349cc55cSDimitry Andric     else
177349cc55cSDimitry Andric       platform_id = OSPlatform::Linux;
178349cc55cSDimitry Andric     break;
179349cc55cSDimitry Andric   case llvm::Triple::OSType::Win32:
180349cc55cSDimitry Andric     platform_id = OSPlatform::Win32NT;
181349cc55cSDimitry Andric     break;
182349cc55cSDimitry Andric   case llvm::Triple::OSType::MacOSX:
183349cc55cSDimitry Andric     platform_id = OSPlatform::MacOSX;
184349cc55cSDimitry Andric     break;
185349cc55cSDimitry Andric   case llvm::Triple::OSType::IOS:
186349cc55cSDimitry Andric     platform_id = OSPlatform::IOS;
187349cc55cSDimitry Andric     break;
188349cc55cSDimitry Andric   default:
189349cc55cSDimitry Andric     error.SetErrorStringWithFormat("OS %s not supported.",
190349cc55cSDimitry Andric                                    target_triple.getOSName().str().c_str());
191349cc55cSDimitry Andric     return error;
192349cc55cSDimitry Andric   };
193349cc55cSDimitry Andric 
194349cc55cSDimitry Andric   llvm::minidump::SystemInfo sys_info;
195349cc55cSDimitry Andric   sys_info.ProcessorArch =
196349cc55cSDimitry Andric       static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch);
197349cc55cSDimitry Andric   // Global offset to beginning of a csd_string in a data section
198349cc55cSDimitry Andric   sys_info.CSDVersionRVA = static_cast<llvm::support::ulittle32_t>(
199349cc55cSDimitry Andric       GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo));
200349cc55cSDimitry Andric   sys_info.PlatformId = platform_id;
201349cc55cSDimitry Andric   m_data.AppendData(&sys_info, sizeof(llvm::minidump::SystemInfo));
202349cc55cSDimitry Andric 
20304eeddc0SDimitry Andric   std::string csd_string;
204349cc55cSDimitry Andric 
205349cc55cSDimitry Andric   error = WriteString(csd_string, &m_data);
206349cc55cSDimitry Andric   if (error.Fail()) {
207349cc55cSDimitry Andric     error.SetErrorString("Unable to convert the csd string to UTF16.");
208349cc55cSDimitry Andric     return error;
209349cc55cSDimitry Andric   }
210349cc55cSDimitry Andric 
211349cc55cSDimitry Andric   return error;
212349cc55cSDimitry Andric }
213349cc55cSDimitry Andric 
214349cc55cSDimitry Andric Status WriteString(const std::string &to_write,
215349cc55cSDimitry Andric                    lldb_private::DataBufferHeap *buffer) {
216349cc55cSDimitry Andric   Status error;
217349cc55cSDimitry Andric   // let the StringRef eat also null termination char
218349cc55cSDimitry Andric   llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1);
219349cc55cSDimitry Andric   llvm::SmallVector<llvm::UTF16, 128> to_write_utf16;
220349cc55cSDimitry Andric 
221349cc55cSDimitry Andric   bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16);
222349cc55cSDimitry Andric   if (!converted) {
223349cc55cSDimitry Andric     error.SetErrorStringWithFormat(
224349cc55cSDimitry Andric         "Unable to convert the string to UTF16. Failed to convert %s",
225349cc55cSDimitry Andric         to_write.c_str());
226349cc55cSDimitry Andric     return error;
227349cc55cSDimitry Andric   }
228349cc55cSDimitry Andric 
229349cc55cSDimitry Andric   // size of the UTF16 string should be written without the null termination
230349cc55cSDimitry Andric   // character that is stored in 2 bytes
231349cc55cSDimitry Andric   llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2);
232349cc55cSDimitry Andric 
233349cc55cSDimitry Andric   buffer->AppendData(&to_write_size, sizeof(llvm::support::ulittle32_t));
234349cc55cSDimitry Andric   buffer->AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes());
235349cc55cSDimitry Andric 
236349cc55cSDimitry Andric   return error;
237349cc55cSDimitry Andric }
238349cc55cSDimitry Andric 
239349cc55cSDimitry Andric llvm::Expected<uint64_t> getModuleFileSize(Target &target,
240349cc55cSDimitry Andric                                            const ModuleSP &mod) {
241*0fca6ea1SDimitry Andric   // JIT module has the same vm and file size.
242349cc55cSDimitry Andric   uint64_t SizeOfImage = 0;
243*0fca6ea1SDimitry Andric   if (mod->GetObjectFile()->CalculateType() == ObjectFile::Type::eTypeJIT) {
244*0fca6ea1SDimitry Andric     for (const auto &section : *mod->GetObjectFile()->GetSectionList()) {
245*0fca6ea1SDimitry Andric       SizeOfImage += section->GetByteSize();
246*0fca6ea1SDimitry Andric     }
247*0fca6ea1SDimitry Andric     return SizeOfImage;
248*0fca6ea1SDimitry Andric   }
249*0fca6ea1SDimitry Andric   SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection();
250349cc55cSDimitry Andric 
251349cc55cSDimitry Andric   if (!sect_sp) {
252349cc55cSDimitry Andric     return llvm::createStringError(std::errc::operation_not_supported,
253349cc55cSDimitry Andric                                    "Couldn't obtain the section information.");
254349cc55cSDimitry Andric   }
255349cc55cSDimitry Andric   lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target);
256349cc55cSDimitry Andric   // Use memory size since zero fill sections, like ".bss", will be smaller on
257349cc55cSDimitry Andric   // disk.
258349cc55cSDimitry Andric   lldb::addr_t sect_size = sect_sp->GetByteSize();
259349cc55cSDimitry Andric   // This will usually be zero, but make sure to calculate the BaseOfImage
260349cc55cSDimitry Andric   // offset.
261349cc55cSDimitry Andric   const lldb::addr_t base_sect_offset =
262349cc55cSDimitry Andric       mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) -
263349cc55cSDimitry Andric       sect_addr;
264349cc55cSDimitry Andric   SizeOfImage = sect_size - base_sect_offset;
265349cc55cSDimitry Andric   lldb::addr_t next_sect_addr = sect_addr + sect_size;
266349cc55cSDimitry Andric   Address sect_so_addr;
267349cc55cSDimitry Andric   target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
268349cc55cSDimitry Andric   lldb::SectionSP next_sect_sp = sect_so_addr.GetSection();
269349cc55cSDimitry Andric   while (next_sect_sp &&
270349cc55cSDimitry Andric          next_sect_sp->GetLoadBaseAddress(&target) == next_sect_addr) {
271349cc55cSDimitry Andric     sect_size = sect_sp->GetByteSize();
272349cc55cSDimitry Andric     SizeOfImage += sect_size;
273349cc55cSDimitry Andric     next_sect_addr += sect_size;
274349cc55cSDimitry Andric     target.ResolveLoadAddress(next_sect_addr, sect_so_addr);
275349cc55cSDimitry Andric     next_sect_sp = sect_so_addr.GetSection();
276349cc55cSDimitry Andric   }
277349cc55cSDimitry Andric 
278349cc55cSDimitry Andric   return SizeOfImage;
279349cc55cSDimitry Andric }
280349cc55cSDimitry Andric 
281349cc55cSDimitry Andric // ModuleList stream consists of a number of modules, followed by an array
282349cc55cSDimitry Andric // of llvm::minidump::Module's structures. Every structure informs about a
283349cc55cSDimitry Andric // single module. Additional data of variable length, such as module's names,
284349cc55cSDimitry Andric // are stored just after the ModuleList stream. The llvm::minidump::Module
285349cc55cSDimitry Andric // structures point to this helper data by global offset.
286*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddModuleList() {
287349cc55cSDimitry Andric   constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module);
288349cc55cSDimitry Andric   Status error;
289349cc55cSDimitry Andric 
290*0fca6ea1SDimitry Andric   lldb_private::Target &target = m_process_sp->GetTarget();
291349cc55cSDimitry Andric   const ModuleList &modules = target.GetImages();
292349cc55cSDimitry Andric   llvm::support::ulittle32_t modules_count =
293349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(modules.GetSize());
294349cc55cSDimitry Andric 
295349cc55cSDimitry Andric   // This helps us with getting the correct global offset in minidump
296349cc55cSDimitry Andric   // file later, when we will be setting up offsets from the
297349cc55cSDimitry Andric   // the llvm::minidump::Module's structures into helper data
298349cc55cSDimitry Andric   size_t size_before = GetCurrentDataEndOffset();
299349cc55cSDimitry Andric 
300349cc55cSDimitry Andric   // This is the size of the main part of the ModuleList stream.
301349cc55cSDimitry Andric   // It consists of a module number and corresponding number of
302349cc55cSDimitry Andric   // structs describing individual modules
303349cc55cSDimitry Andric   size_t module_stream_size =
304349cc55cSDimitry Andric       sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size;
305349cc55cSDimitry Andric 
306349cc55cSDimitry Andric   // Adding directory describing this stream.
307*0fca6ea1SDimitry Andric   error = AddDirectory(StreamType::ModuleList, module_stream_size);
308*0fca6ea1SDimitry Andric   if (error.Fail())
309*0fca6ea1SDimitry Andric     return error;
310349cc55cSDimitry Andric 
311349cc55cSDimitry Andric   m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t));
312349cc55cSDimitry Andric 
313349cc55cSDimitry Andric   // Temporary storage for the helper data (of variable length)
314349cc55cSDimitry Andric   // as these cannot be dumped to m_data before dumping entire
315349cc55cSDimitry Andric   // array of module structures.
316349cc55cSDimitry Andric   DataBufferHeap helper_data;
317349cc55cSDimitry Andric 
318349cc55cSDimitry Andric   for (size_t i = 0; i < modules_count; ++i) {
319349cc55cSDimitry Andric     ModuleSP mod = modules.GetModuleAtIndex(i);
320349cc55cSDimitry Andric     std::string module_name = mod->GetSpecificationDescription();
321349cc55cSDimitry Andric     auto maybe_mod_size = getModuleFileSize(target, mod);
322349cc55cSDimitry Andric     if (!maybe_mod_size) {
323*0fca6ea1SDimitry Andric       llvm::Error mod_size_err = maybe_mod_size.takeError();
324*0fca6ea1SDimitry Andric       llvm::handleAllErrors(std::move(mod_size_err),
325*0fca6ea1SDimitry Andric                             [&](const llvm::ErrorInfoBase &E) {
326*0fca6ea1SDimitry Andric                               error.SetErrorStringWithFormat(
327*0fca6ea1SDimitry Andric                                   "Unable to get the size of module %s: %s.",
328*0fca6ea1SDimitry Andric                                   module_name.c_str(), E.message().c_str());
329*0fca6ea1SDimitry Andric                             });
330349cc55cSDimitry Andric       return error;
331349cc55cSDimitry Andric     }
332349cc55cSDimitry Andric 
333349cc55cSDimitry Andric     uint64_t mod_size = std::move(*maybe_mod_size);
334349cc55cSDimitry Andric 
335349cc55cSDimitry Andric     llvm::support::ulittle32_t signature =
336349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(
337349cc55cSDimitry Andric             static_cast<uint32_t>(minidump::CvSignature::ElfBuildId));
338349cc55cSDimitry Andric     auto uuid = mod->GetUUID().GetBytes();
339349cc55cSDimitry Andric 
340349cc55cSDimitry Andric     VSFixedFileInfo info;
341349cc55cSDimitry Andric     info.Signature = static_cast<llvm::support::ulittle32_t>(0u);
342349cc55cSDimitry Andric     info.StructVersion = static_cast<llvm::support::ulittle32_t>(0u);
343349cc55cSDimitry Andric     info.FileVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
344349cc55cSDimitry Andric     info.FileVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
345349cc55cSDimitry Andric     info.ProductVersionHigh = static_cast<llvm::support::ulittle32_t>(0u);
346349cc55cSDimitry Andric     info.ProductVersionLow = static_cast<llvm::support::ulittle32_t>(0u);
347349cc55cSDimitry Andric     info.FileFlagsMask = static_cast<llvm::support::ulittle32_t>(0u);
348349cc55cSDimitry Andric     info.FileFlags = static_cast<llvm::support::ulittle32_t>(0u);
349349cc55cSDimitry Andric     info.FileOS = static_cast<llvm::support::ulittle32_t>(0u);
350349cc55cSDimitry Andric     info.FileType = static_cast<llvm::support::ulittle32_t>(0u);
351349cc55cSDimitry Andric     info.FileSubtype = static_cast<llvm::support::ulittle32_t>(0u);
352349cc55cSDimitry Andric     info.FileDateHigh = static_cast<llvm::support::ulittle32_t>(0u);
353349cc55cSDimitry Andric     info.FileDateLow = static_cast<llvm::support::ulittle32_t>(0u);
354349cc55cSDimitry Andric 
355349cc55cSDimitry Andric     LocationDescriptor ld;
356349cc55cSDimitry Andric     ld.DataSize = static_cast<llvm::support::ulittle32_t>(0u);
357349cc55cSDimitry Andric     ld.RVA = static_cast<llvm::support::ulittle32_t>(0u);
358349cc55cSDimitry Andric 
359349cc55cSDimitry Andric     // Setting up LocationDescriptor for uuid string. The global offset into
360349cc55cSDimitry Andric     // minidump file is calculated.
361349cc55cSDimitry Andric     LocationDescriptor ld_cv;
362349cc55cSDimitry Andric     ld_cv.DataSize = static_cast<llvm::support::ulittle32_t>(
363349cc55cSDimitry Andric         sizeof(llvm::support::ulittle32_t) + uuid.size());
364349cc55cSDimitry Andric     ld_cv.RVA = static_cast<llvm::support::ulittle32_t>(
365349cc55cSDimitry Andric         size_before + module_stream_size + helper_data.GetByteSize());
366349cc55cSDimitry Andric 
367349cc55cSDimitry Andric     helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t));
368349cc55cSDimitry Andric     helper_data.AppendData(uuid.begin(), uuid.size());
369349cc55cSDimitry Andric 
370349cc55cSDimitry Andric     llvm::minidump::Module m;
371349cc55cSDimitry Andric     m.BaseOfImage = static_cast<llvm::support::ulittle64_t>(
372349cc55cSDimitry Andric         mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target));
373349cc55cSDimitry Andric     m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size);
374349cc55cSDimitry Andric     m.Checksum = static_cast<llvm::support::ulittle32_t>(0);
37504eeddc0SDimitry Andric     m.TimeDateStamp =
37604eeddc0SDimitry Andric         static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
377349cc55cSDimitry Andric     m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>(
378349cc55cSDimitry Andric         size_before + module_stream_size + helper_data.GetByteSize());
379349cc55cSDimitry Andric     m.VersionInfo = info;
380349cc55cSDimitry Andric     m.CvRecord = ld_cv;
381349cc55cSDimitry Andric     m.MiscRecord = ld;
382349cc55cSDimitry Andric 
383349cc55cSDimitry Andric     error = WriteString(module_name, &helper_data);
384349cc55cSDimitry Andric 
385349cc55cSDimitry Andric     if (error.Fail())
386349cc55cSDimitry Andric       return error;
387349cc55cSDimitry Andric 
388349cc55cSDimitry Andric     m_data.AppendData(&m, sizeof(llvm::minidump::Module));
389349cc55cSDimitry Andric   }
390349cc55cSDimitry Andric 
391349cc55cSDimitry Andric   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
392349cc55cSDimitry Andric   return error;
393349cc55cSDimitry Andric }
394349cc55cSDimitry Andric 
395349cc55cSDimitry Andric uint16_t read_register_u16_raw(RegisterContext *reg_ctx,
3965f757f3fSDimitry Andric                                llvm::StringRef reg_name) {
397349cc55cSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
398349cc55cSDimitry Andric   if (!reg_info)
399349cc55cSDimitry Andric     return 0;
400349cc55cSDimitry Andric   lldb_private::RegisterValue reg_value;
401349cc55cSDimitry Andric   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
402349cc55cSDimitry Andric   if (!success)
403349cc55cSDimitry Andric     return 0;
404349cc55cSDimitry Andric   return reg_value.GetAsUInt16();
405349cc55cSDimitry Andric }
406349cc55cSDimitry Andric 
407349cc55cSDimitry Andric uint32_t read_register_u32_raw(RegisterContext *reg_ctx,
4085f757f3fSDimitry Andric                                llvm::StringRef reg_name) {
409349cc55cSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
410349cc55cSDimitry Andric   if (!reg_info)
411349cc55cSDimitry Andric     return 0;
412349cc55cSDimitry Andric   lldb_private::RegisterValue reg_value;
413349cc55cSDimitry Andric   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
414349cc55cSDimitry Andric   if (!success)
415349cc55cSDimitry Andric     return 0;
416349cc55cSDimitry Andric   return reg_value.GetAsUInt32();
417349cc55cSDimitry Andric }
418349cc55cSDimitry Andric 
419349cc55cSDimitry Andric uint64_t read_register_u64_raw(RegisterContext *reg_ctx,
4205f757f3fSDimitry Andric                                llvm::StringRef reg_name) {
421349cc55cSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
422349cc55cSDimitry Andric   if (!reg_info)
423349cc55cSDimitry Andric     return 0;
424349cc55cSDimitry Andric   lldb_private::RegisterValue reg_value;
425349cc55cSDimitry Andric   bool success = reg_ctx->ReadRegister(reg_info, reg_value);
426349cc55cSDimitry Andric   if (!success)
427349cc55cSDimitry Andric     return 0;
428349cc55cSDimitry Andric   return reg_value.GetAsUInt64();
429349cc55cSDimitry Andric }
430349cc55cSDimitry Andric 
431349cc55cSDimitry Andric llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx,
4325f757f3fSDimitry Andric                                              llvm::StringRef reg_name) {
433349cc55cSDimitry Andric   return static_cast<llvm::support::ulittle16_t>(
434349cc55cSDimitry Andric       read_register_u16_raw(reg_ctx, reg_name));
435349cc55cSDimitry Andric }
436349cc55cSDimitry Andric 
437349cc55cSDimitry Andric llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx,
4385f757f3fSDimitry Andric                                              llvm::StringRef reg_name) {
439349cc55cSDimitry Andric   return static_cast<llvm::support::ulittle32_t>(
440349cc55cSDimitry Andric       read_register_u32_raw(reg_ctx, reg_name));
441349cc55cSDimitry Andric }
442349cc55cSDimitry Andric 
443349cc55cSDimitry Andric llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx,
4445f757f3fSDimitry Andric                                              llvm::StringRef reg_name) {
445349cc55cSDimitry Andric   return static_cast<llvm::support::ulittle64_t>(
446349cc55cSDimitry Andric       read_register_u64_raw(reg_ctx, reg_name));
447349cc55cSDimitry Andric }
448349cc55cSDimitry Andric 
4495f757f3fSDimitry Andric void read_register_u128(RegisterContext *reg_ctx, llvm::StringRef reg_name,
4505f757f3fSDimitry Andric                         uint8_t *dst) {
4515f757f3fSDimitry Andric   const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
4525f757f3fSDimitry Andric   if (reg_info) {
4535f757f3fSDimitry Andric     lldb_private::RegisterValue reg_value;
4545f757f3fSDimitry Andric     if (reg_ctx->ReadRegister(reg_info, reg_value)) {
4555f757f3fSDimitry Andric       Status error;
4565f757f3fSDimitry Andric       uint32_t bytes_copied = reg_value.GetAsMemoryData(
4575f757f3fSDimitry Andric           *reg_info, dst, 16, lldb::ByteOrder::eByteOrderLittle, error);
4585f757f3fSDimitry Andric       if (bytes_copied == 16)
4595f757f3fSDimitry Andric         return;
4605f757f3fSDimitry Andric     }
4615f757f3fSDimitry Andric   }
4625f757f3fSDimitry Andric   // If anything goes wrong, then zero out the register value.
4635f757f3fSDimitry Andric   memset(dst, 0, 16);
4645f757f3fSDimitry Andric }
4655f757f3fSDimitry Andric 
466349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64
4675f757f3fSDimitry Andric GetThreadContext_x86_64(RegisterContext *reg_ctx) {
468972a253aSDimitry Andric   lldb_private::minidump::MinidumpContext_x86_64 thread_context = {};
469fcaf7f86SDimitry Andric   thread_context.p1_home = {};
470349cc55cSDimitry Andric   thread_context.context_flags = static_cast<uint32_t>(
471349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag |
472349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::Control |
473349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::Segments |
474349cc55cSDimitry Andric       lldb_private::minidump::MinidumpContext_x86_64_Flags::Integer);
475349cc55cSDimitry Andric   thread_context.rax = read_register_u64(reg_ctx, "rax");
476349cc55cSDimitry Andric   thread_context.rbx = read_register_u64(reg_ctx, "rbx");
477349cc55cSDimitry Andric   thread_context.rcx = read_register_u64(reg_ctx, "rcx");
478349cc55cSDimitry Andric   thread_context.rdx = read_register_u64(reg_ctx, "rdx");
479349cc55cSDimitry Andric   thread_context.rdi = read_register_u64(reg_ctx, "rdi");
480349cc55cSDimitry Andric   thread_context.rsi = read_register_u64(reg_ctx, "rsi");
481349cc55cSDimitry Andric   thread_context.rbp = read_register_u64(reg_ctx, "rbp");
482349cc55cSDimitry Andric   thread_context.rsp = read_register_u64(reg_ctx, "rsp");
483349cc55cSDimitry Andric   thread_context.r8 = read_register_u64(reg_ctx, "r8");
484349cc55cSDimitry Andric   thread_context.r9 = read_register_u64(reg_ctx, "r9");
485349cc55cSDimitry Andric   thread_context.r10 = read_register_u64(reg_ctx, "r10");
486349cc55cSDimitry Andric   thread_context.r11 = read_register_u64(reg_ctx, "r11");
487349cc55cSDimitry Andric   thread_context.r12 = read_register_u64(reg_ctx, "r12");
488349cc55cSDimitry Andric   thread_context.r13 = read_register_u64(reg_ctx, "r13");
489349cc55cSDimitry Andric   thread_context.r14 = read_register_u64(reg_ctx, "r14");
490349cc55cSDimitry Andric   thread_context.r15 = read_register_u64(reg_ctx, "r15");
491349cc55cSDimitry Andric   thread_context.rip = read_register_u64(reg_ctx, "rip");
492349cc55cSDimitry Andric   thread_context.eflags = read_register_u32(reg_ctx, "rflags");
493349cc55cSDimitry Andric   thread_context.cs = read_register_u16(reg_ctx, "cs");
494349cc55cSDimitry Andric   thread_context.fs = read_register_u16(reg_ctx, "fs");
495349cc55cSDimitry Andric   thread_context.gs = read_register_u16(reg_ctx, "gs");
496349cc55cSDimitry Andric   thread_context.ss = read_register_u16(reg_ctx, "ss");
497349cc55cSDimitry Andric   thread_context.ds = read_register_u16(reg_ctx, "ds");
498349cc55cSDimitry Andric   return thread_context;
499349cc55cSDimitry Andric }
500349cc55cSDimitry Andric 
5015f757f3fSDimitry Andric minidump::RegisterContextMinidump_ARM64::Context
5025f757f3fSDimitry Andric GetThreadContext_ARM64(RegisterContext *reg_ctx) {
5035f757f3fSDimitry Andric   minidump::RegisterContextMinidump_ARM64::Context thread_context = {};
5045f757f3fSDimitry Andric   thread_context.context_flags = static_cast<uint32_t>(
5055f757f3fSDimitry Andric       minidump::RegisterContextMinidump_ARM64::Flags::ARM64_Flag |
5065f757f3fSDimitry Andric       minidump::RegisterContextMinidump_ARM64::Flags::Integer |
5075f757f3fSDimitry Andric       minidump::RegisterContextMinidump_ARM64::Flags::FloatingPoint);
5085f757f3fSDimitry Andric   char reg_name[16];
5095f757f3fSDimitry Andric   for (uint32_t i = 0; i < 31; ++i) {
5105f757f3fSDimitry Andric     snprintf(reg_name, sizeof(reg_name), "x%u", i);
5115f757f3fSDimitry Andric     thread_context.x[i] = read_register_u64(reg_ctx, reg_name);
5125f757f3fSDimitry Andric   }
5135f757f3fSDimitry Andric   // Work around a bug in debugserver where "sp" on arm64 doesn't have the alt
5145f757f3fSDimitry Andric   // name set to "x31"
5155f757f3fSDimitry Andric   thread_context.x[31] = read_register_u64(reg_ctx, "sp");
5165f757f3fSDimitry Andric   thread_context.pc = read_register_u64(reg_ctx, "pc");
5175f757f3fSDimitry Andric   thread_context.cpsr = read_register_u32(reg_ctx, "cpsr");
5185f757f3fSDimitry Andric   thread_context.fpsr = read_register_u32(reg_ctx, "fpsr");
5195f757f3fSDimitry Andric   thread_context.fpcr = read_register_u32(reg_ctx, "fpcr");
5205f757f3fSDimitry Andric   for (uint32_t i = 0; i < 32; ++i) {
5215f757f3fSDimitry Andric     snprintf(reg_name, sizeof(reg_name), "v%u", i);
5225f757f3fSDimitry Andric     read_register_u128(reg_ctx, reg_name, &thread_context.v[i * 16]);
5235f757f3fSDimitry Andric   }
5245f757f3fSDimitry Andric   return thread_context;
5255f757f3fSDimitry Andric }
5265f757f3fSDimitry Andric 
5275f757f3fSDimitry Andric class ArchThreadContexts {
5285f757f3fSDimitry Andric   llvm::Triple::ArchType m_arch;
5295f757f3fSDimitry Andric   union {
5305f757f3fSDimitry Andric     lldb_private::minidump::MinidumpContext_x86_64 x86_64;
5315f757f3fSDimitry Andric     lldb_private::minidump::RegisterContextMinidump_ARM64::Context arm64;
5325f757f3fSDimitry Andric   };
5335f757f3fSDimitry Andric 
5345f757f3fSDimitry Andric public:
5355f757f3fSDimitry Andric   ArchThreadContexts(llvm::Triple::ArchType arch) : m_arch(arch) {}
5365f757f3fSDimitry Andric 
5375f757f3fSDimitry Andric   bool prepareRegisterContext(RegisterContext *reg_ctx) {
5385f757f3fSDimitry Andric     switch (m_arch) {
5395f757f3fSDimitry Andric     case llvm::Triple::ArchType::x86_64:
5405f757f3fSDimitry Andric       x86_64 = GetThreadContext_x86_64(reg_ctx);
5415f757f3fSDimitry Andric       return true;
5425f757f3fSDimitry Andric     case llvm::Triple::ArchType::aarch64:
5435f757f3fSDimitry Andric       arm64 = GetThreadContext_ARM64(reg_ctx);
5445f757f3fSDimitry Andric       return true;
5455f757f3fSDimitry Andric     default:
5465f757f3fSDimitry Andric       break;
5475f757f3fSDimitry Andric     }
5485f757f3fSDimitry Andric     return false;
5495f757f3fSDimitry Andric   }
5505f757f3fSDimitry Andric 
5515f757f3fSDimitry Andric   const void *data() const { return &x86_64; }
5525f757f3fSDimitry Andric 
5535f757f3fSDimitry Andric   size_t size() const {
5545f757f3fSDimitry Andric     switch (m_arch) {
5555f757f3fSDimitry Andric     case llvm::Triple::ArchType::x86_64:
5565f757f3fSDimitry Andric       return sizeof(x86_64);
5575f757f3fSDimitry Andric     case llvm::Triple::ArchType::aarch64:
5585f757f3fSDimitry Andric       return sizeof(arm64);
5595f757f3fSDimitry Andric     default:
5605f757f3fSDimitry Andric       break;
5615f757f3fSDimitry Andric     }
5625f757f3fSDimitry Andric     return 0;
5635f757f3fSDimitry Andric   }
5645f757f3fSDimitry Andric };
5655f757f3fSDimitry Andric 
566*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::FixThreadStacks() {
567*0fca6ea1SDimitry Andric   Status error;
568*0fca6ea1SDimitry Andric   // If we have anything in the heap flush it.
569*0fca6ea1SDimitry Andric   FlushBufferToDisk();
570*0fca6ea1SDimitry Andric   m_core_file->SeekFromStart(m_thread_list_start);
571*0fca6ea1SDimitry Andric   for (auto &pair : m_thread_by_range_end) {
572*0fca6ea1SDimitry Andric     // The thread objects will get a new memory descriptor added
573*0fca6ea1SDimitry Andric     // When we are emitting the memory list and then we write it here
574*0fca6ea1SDimitry Andric     const llvm::minidump::Thread &thread = pair.second;
575*0fca6ea1SDimitry Andric     size_t bytes_to_write = sizeof(llvm::minidump::Thread);
576*0fca6ea1SDimitry Andric     size_t bytes_written = bytes_to_write;
577*0fca6ea1SDimitry Andric     error = m_core_file->Write(&thread, bytes_written);
578*0fca6ea1SDimitry Andric     if (error.Fail() || bytes_to_write != bytes_written) {
579*0fca6ea1SDimitry Andric       error.SetErrorStringWithFormat(
580*0fca6ea1SDimitry Andric           "Wrote incorrect number of bytes to minidump file. (written %zd/%zd)",
581*0fca6ea1SDimitry Andric           bytes_written, bytes_to_write);
582*0fca6ea1SDimitry Andric       return error;
583*0fca6ea1SDimitry Andric     }
584349cc55cSDimitry Andric   }
585349cc55cSDimitry Andric 
586*0fca6ea1SDimitry Andric   return error;
587*0fca6ea1SDimitry Andric }
588*0fca6ea1SDimitry Andric 
589*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddThreadList() {
590349cc55cSDimitry Andric   constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread);
591*0fca6ea1SDimitry Andric   lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
592349cc55cSDimitry Andric 
593349cc55cSDimitry Andric   // size of the entire thread stream consists of:
594349cc55cSDimitry Andric   // number of threads and threads array
595349cc55cSDimitry Andric   size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) +
596349cc55cSDimitry Andric                               thread_list.GetSize() * minidump_thread_size;
597349cc55cSDimitry Andric   // save for the ability to set up RVA
598349cc55cSDimitry Andric   size_t size_before = GetCurrentDataEndOffset();
599*0fca6ea1SDimitry Andric   Status error;
600*0fca6ea1SDimitry Andric   error = AddDirectory(StreamType::ThreadList, thread_stream_size);
601*0fca6ea1SDimitry Andric   if (error.Fail())
602*0fca6ea1SDimitry Andric     return error;
603349cc55cSDimitry Andric 
604349cc55cSDimitry Andric   llvm::support::ulittle32_t thread_count =
605349cc55cSDimitry Andric       static_cast<llvm::support::ulittle32_t>(thread_list.GetSize());
606349cc55cSDimitry Andric   m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t));
607349cc55cSDimitry Andric 
608*0fca6ea1SDimitry Andric   // Take the offset after the thread count.
609*0fca6ea1SDimitry Andric   m_thread_list_start = GetCurrentDataEndOffset();
610349cc55cSDimitry Andric   DataBufferHeap helper_data;
611349cc55cSDimitry Andric 
612349cc55cSDimitry Andric   const uint32_t num_threads = thread_list.GetSize();
613*0fca6ea1SDimitry Andric   Log *log = GetLog(LLDBLog::Object);
614349cc55cSDimitry Andric   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
615349cc55cSDimitry Andric     ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
616349cc55cSDimitry Andric     RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
617349cc55cSDimitry Andric 
618349cc55cSDimitry Andric     if (!reg_ctx_sp) {
619349cc55cSDimitry Andric       error.SetErrorString("Unable to get the register context.");
620349cc55cSDimitry Andric       return error;
621349cc55cSDimitry Andric     }
622349cc55cSDimitry Andric     RegisterContext *reg_ctx = reg_ctx_sp.get();
623*0fca6ea1SDimitry Andric     Target &target = m_process_sp->GetTarget();
6245f757f3fSDimitry Andric     const ArchSpec &arch = target.GetArchitecture();
6255f757f3fSDimitry Andric     ArchThreadContexts thread_context(arch.GetMachine());
6265f757f3fSDimitry Andric     if (!thread_context.prepareRegisterContext(reg_ctx)) {
6275f757f3fSDimitry Andric       error.SetErrorStringWithFormat(
6285f757f3fSDimitry Andric           "architecture %s not supported.",
6295f757f3fSDimitry Andric           arch.GetTriple().getArchName().str().c_str());
6305f757f3fSDimitry Andric       return error;
6315f757f3fSDimitry Andric     }
632*0fca6ea1SDimitry Andric 
6335f757f3fSDimitry Andric     uint64_t sp = reg_ctx->GetSP();
634*0fca6ea1SDimitry Andric     MemoryRegionInfo sp_region;
635*0fca6ea1SDimitry Andric     m_process_sp->GetMemoryRegionInfo(sp, sp_region);
636349cc55cSDimitry Andric 
637*0fca6ea1SDimitry Andric     // Emit a blank descriptor
638349cc55cSDimitry Andric     MemoryDescriptor stack;
639*0fca6ea1SDimitry Andric     LocationDescriptor empty_label;
640*0fca6ea1SDimitry Andric     empty_label.DataSize = 0;
641*0fca6ea1SDimitry Andric     empty_label.RVA = 0;
642*0fca6ea1SDimitry Andric     stack.Memory = empty_label;
643*0fca6ea1SDimitry Andric     stack.StartOfMemoryRange = 0;
644349cc55cSDimitry Andric     LocationDescriptor thread_context_memory_locator;
645349cc55cSDimitry Andric     thread_context_memory_locator.DataSize =
6465f757f3fSDimitry Andric         static_cast<llvm::support::ulittle32_t>(thread_context.size());
647349cc55cSDimitry Andric     thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>(
648349cc55cSDimitry Andric         size_before + thread_stream_size + helper_data.GetByteSize());
6495f757f3fSDimitry Andric     // Cache thie thread context memory so we can reuse for exceptions.
6505f757f3fSDimitry Andric     m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator;
651349cc55cSDimitry Andric 
652*0fca6ea1SDimitry Andric     LLDB_LOGF(log, "AddThreadList for thread %d: thread_context %zu bytes",
653*0fca6ea1SDimitry Andric               thread_idx, thread_context.size());
6545f757f3fSDimitry Andric     helper_data.AppendData(thread_context.data(), thread_context.size());
655349cc55cSDimitry Andric 
656349cc55cSDimitry Andric     llvm::minidump::Thread t;
657349cc55cSDimitry Andric     t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
658349cc55cSDimitry Andric     t.SuspendCount = static_cast<llvm::support::ulittle32_t>(
659349cc55cSDimitry Andric         (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0);
660349cc55cSDimitry Andric     t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0);
661349cc55cSDimitry Andric     t.Priority = static_cast<llvm::support::ulittle32_t>(0);
662349cc55cSDimitry Andric     t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0);
663349cc55cSDimitry Andric     t.Stack = stack, t.Context = thread_context_memory_locator;
664349cc55cSDimitry Andric 
665*0fca6ea1SDimitry Andric     // We save off the stack object so we can circle back and clean it up.
666*0fca6ea1SDimitry Andric     m_thread_by_range_end[sp_region.GetRange().GetRangeEnd()] = t;
667349cc55cSDimitry Andric     m_data.AppendData(&t, sizeof(llvm::minidump::Thread));
668349cc55cSDimitry Andric   }
669349cc55cSDimitry Andric 
670*0fca6ea1SDimitry Andric   LLDB_LOGF(log, "AddThreadList(): total helper_data %" PRIx64 " bytes",
671*0fca6ea1SDimitry Andric             helper_data.GetByteSize());
672349cc55cSDimitry Andric   m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize());
673349cc55cSDimitry Andric   return Status();
674349cc55cSDimitry Andric }
675349cc55cSDimitry Andric 
676*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddExceptions() {
677*0fca6ea1SDimitry Andric   lldb_private::ThreadList thread_list = m_process_sp->GetThreadList();
678*0fca6ea1SDimitry Andric   Status error;
679349cc55cSDimitry Andric   const uint32_t num_threads = thread_list.GetSize();
6805f757f3fSDimitry Andric   for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) {
6815f757f3fSDimitry Andric     ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
682349cc55cSDimitry Andric     StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
6835f757f3fSDimitry Andric     bool add_exception = false;
6845f757f3fSDimitry Andric     if (stop_info_sp) {
6855f757f3fSDimitry Andric       switch (stop_info_sp->GetStopReason()) {
6865f757f3fSDimitry Andric       case eStopReasonSignal:
6875f757f3fSDimitry Andric       case eStopReasonException:
6885f757f3fSDimitry Andric         add_exception = true;
6895f757f3fSDimitry Andric         break;
6905f757f3fSDimitry Andric       default:
691349cc55cSDimitry Andric         break;
692349cc55cSDimitry Andric       }
693349cc55cSDimitry Andric     }
6945f757f3fSDimitry Andric     if (add_exception) {
695349cc55cSDimitry Andric       constexpr size_t minidump_exception_size =
696349cc55cSDimitry Andric           sizeof(llvm::minidump::ExceptionStream);
697*0fca6ea1SDimitry Andric       error = AddDirectory(StreamType::Exception, minidump_exception_size);
698*0fca6ea1SDimitry Andric       if (error.Fail())
699*0fca6ea1SDimitry Andric         return error;
700*0fca6ea1SDimitry Andric 
701349cc55cSDimitry Andric       StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
7025f757f3fSDimitry Andric       RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext());
703972a253aSDimitry Andric       Exception exp_record = {};
704349cc55cSDimitry Andric       exp_record.ExceptionCode =
705349cc55cSDimitry Andric           static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue());
706349cc55cSDimitry Andric       exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0);
707349cc55cSDimitry Andric       exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0);
7085f757f3fSDimitry Andric       exp_record.ExceptionAddress = reg_ctx_sp->GetPC();
709349cc55cSDimitry Andric       exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0);
710349cc55cSDimitry Andric       exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
711349cc55cSDimitry Andric       // exp_record.ExceptionInformation;
712349cc55cSDimitry Andric 
713349cc55cSDimitry Andric       ExceptionStream exp_stream;
714349cc55cSDimitry Andric       exp_stream.ThreadId =
715349cc55cSDimitry Andric           static_cast<llvm::support::ulittle32_t>(thread_sp->GetID());
716349cc55cSDimitry Andric       exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0);
717349cc55cSDimitry Andric       exp_stream.ExceptionRecord = exp_record;
7185f757f3fSDimitry Andric       auto Iter = m_tid_to_reg_ctx.find(thread_sp->GetID());
7195f757f3fSDimitry Andric       if (Iter != m_tid_to_reg_ctx.end()) {
7205f757f3fSDimitry Andric         exp_stream.ThreadContext = Iter->second;
7215f757f3fSDimitry Andric       } else {
7225f757f3fSDimitry Andric         exp_stream.ThreadContext.DataSize = 0;
7235f757f3fSDimitry Andric         exp_stream.ThreadContext.RVA = 0;
7245f757f3fSDimitry Andric       }
725349cc55cSDimitry Andric       m_data.AppendData(&exp_stream, minidump_exception_size);
7265f757f3fSDimitry Andric     }
7275f757f3fSDimitry Andric   }
728*0fca6ea1SDimitry Andric 
729*0fca6ea1SDimitry Andric   return error;
730349cc55cSDimitry Andric }
731349cc55cSDimitry Andric 
732*0fca6ea1SDimitry Andric lldb_private::Status MinidumpFileBuilder::AddMiscInfo() {
733349cc55cSDimitry Andric   Status error;
734*0fca6ea1SDimitry Andric   error = AddDirectory(StreamType::MiscInfo,
735349cc55cSDimitry Andric                        sizeof(lldb_private::minidump::MinidumpMiscInfo));
736*0fca6ea1SDimitry Andric   if (error.Fail())
737*0fca6ea1SDimitry Andric     return error;
738349cc55cSDimitry Andric 
739349cc55cSDimitry Andric   lldb_private::minidump::MinidumpMiscInfo misc_info;
740349cc55cSDimitry Andric   misc_info.size = static_cast<llvm::support::ulittle32_t>(
741349cc55cSDimitry Andric       sizeof(lldb_private::minidump::MinidumpMiscInfo));
742349cc55cSDimitry Andric   // Default set flags1 to 0, in case that we will not be able to
743349cc55cSDimitry Andric   // get any information
744349cc55cSDimitry Andric   misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0);
745349cc55cSDimitry Andric 
746349cc55cSDimitry Andric   lldb_private::ProcessInstanceInfo process_info;
747*0fca6ea1SDimitry Andric   m_process_sp->GetProcessInfo(process_info);
748349cc55cSDimitry Andric   if (process_info.ProcessIDIsValid()) {
749349cc55cSDimitry Andric     // Set flags1 to reflect that PID is filled in
750349cc55cSDimitry Andric     misc_info.flags1 =
751349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>(
752349cc55cSDimitry Andric             lldb_private::minidump::MinidumpMiscInfoFlags::ProcessID));
753349cc55cSDimitry Andric     misc_info.process_id =
754349cc55cSDimitry Andric         static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID());
755349cc55cSDimitry Andric   }
756349cc55cSDimitry Andric 
757349cc55cSDimitry Andric   m_data.AppendData(&misc_info,
758349cc55cSDimitry Andric                     sizeof(lldb_private::minidump::MinidumpMiscInfo));
759*0fca6ea1SDimitry Andric   return error;
760349cc55cSDimitry Andric }
761349cc55cSDimitry Andric 
762349cc55cSDimitry Andric std::unique_ptr<llvm::MemoryBuffer>
763349cc55cSDimitry Andric getFileStreamHelper(const std::string &path) {
764349cc55cSDimitry Andric   auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path);
765349cc55cSDimitry Andric   if (!maybe_stream)
766349cc55cSDimitry Andric     return nullptr;
767349cc55cSDimitry Andric   return std::move(maybe_stream.get());
768349cc55cSDimitry Andric }
769349cc55cSDimitry Andric 
770*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddLinuxFileStreams() {
771*0fca6ea1SDimitry Andric   Status error;
772*0fca6ea1SDimitry Andric   // No-op if we are not on linux.
773*0fca6ea1SDimitry Andric   if (m_process_sp->GetTarget().GetArchitecture().GetTriple().getOS() !=
774*0fca6ea1SDimitry Andric       llvm::Triple::Linux)
775*0fca6ea1SDimitry Andric     return error;
776*0fca6ea1SDimitry Andric 
777349cc55cSDimitry Andric   std::vector<std::pair<StreamType, std::string>> files_with_stream_types = {
778349cc55cSDimitry Andric       {StreamType::LinuxCPUInfo, "/proc/cpuinfo"},
779349cc55cSDimitry Andric       {StreamType::LinuxLSBRelease, "/etc/lsb-release"},
780349cc55cSDimitry Andric   };
781349cc55cSDimitry Andric 
782349cc55cSDimitry Andric   lldb_private::ProcessInstanceInfo process_info;
783*0fca6ea1SDimitry Andric   m_process_sp->GetProcessInfo(process_info);
784349cc55cSDimitry Andric   if (process_info.ProcessIDIsValid()) {
785349cc55cSDimitry Andric     lldb::pid_t pid = process_info.GetProcessID();
786349cc55cSDimitry Andric     std::string pid_str = std::to_string(pid);
787349cc55cSDimitry Andric     files_with_stream_types.push_back(
788349cc55cSDimitry Andric         {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"});
789349cc55cSDimitry Andric     files_with_stream_types.push_back(
790349cc55cSDimitry Andric         {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"});
791349cc55cSDimitry Andric     files_with_stream_types.push_back(
792349cc55cSDimitry Andric         {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"});
793349cc55cSDimitry Andric     files_with_stream_types.push_back(
794349cc55cSDimitry Andric         {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"});
795349cc55cSDimitry Andric     files_with_stream_types.push_back(
796349cc55cSDimitry Andric         {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"});
797349cc55cSDimitry Andric     files_with_stream_types.push_back(
798349cc55cSDimitry Andric         {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"});
799349cc55cSDimitry Andric     files_with_stream_types.push_back(
800349cc55cSDimitry Andric         {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"});
801349cc55cSDimitry Andric   }
802349cc55cSDimitry Andric 
803349cc55cSDimitry Andric   for (const auto &entry : files_with_stream_types) {
804349cc55cSDimitry Andric     StreamType stream = entry.first;
805349cc55cSDimitry Andric     std::string path = entry.second;
806349cc55cSDimitry Andric     auto memory_buffer = getFileStreamHelper(path);
807349cc55cSDimitry Andric 
808349cc55cSDimitry Andric     if (memory_buffer) {
809349cc55cSDimitry Andric       size_t size = memory_buffer->getBufferSize();
810349cc55cSDimitry Andric       if (size == 0)
811349cc55cSDimitry Andric         continue;
812*0fca6ea1SDimitry Andric       error = AddDirectory(stream, size);
813*0fca6ea1SDimitry Andric       if (error.Fail())
814*0fca6ea1SDimitry Andric         return error;
815349cc55cSDimitry Andric       m_data.AppendData(memory_buffer->getBufferStart(), size);
816349cc55cSDimitry Andric     }
817349cc55cSDimitry Andric   }
818*0fca6ea1SDimitry Andric 
819*0fca6ea1SDimitry Andric   return error;
820349cc55cSDimitry Andric }
821349cc55cSDimitry Andric 
822*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddMemoryList(SaveCoreStyle core_style) {
823*0fca6ea1SDimitry Andric   Status error;
824349cc55cSDimitry Andric 
825*0fca6ea1SDimitry Andric   // We first save the thread stacks to ensure they fit in the first UINT32_MAX
826*0fca6ea1SDimitry Andric   // bytes of the core file. Thread structures in minidump files can only use
827*0fca6ea1SDimitry Andric   // 32 bit memory descriptiors, so we emit them first to ensure the memory is
828*0fca6ea1SDimitry Andric   // in accessible with a 32 bit offset.
829*0fca6ea1SDimitry Andric   Process::CoreFileMemoryRanges ranges_32;
830*0fca6ea1SDimitry Andric   Process::CoreFileMemoryRanges ranges_64;
831*0fca6ea1SDimitry Andric   error = m_process_sp->CalculateCoreFileSaveRanges(
832*0fca6ea1SDimitry Andric       SaveCoreStyle::eSaveCoreStackOnly, ranges_32);
833*0fca6ea1SDimitry Andric   if (error.Fail())
834*0fca6ea1SDimitry Andric     return error;
835*0fca6ea1SDimitry Andric 
836*0fca6ea1SDimitry Andric   // Calculate totalsize including the current offset.
837*0fca6ea1SDimitry Andric   uint64_t total_size = GetCurrentDataEndOffset();
838*0fca6ea1SDimitry Andric   total_size += ranges_32.size() * sizeof(llvm::minidump::MemoryDescriptor);
839*0fca6ea1SDimitry Andric   std::unordered_set<addr_t> stack_start_addresses;
840*0fca6ea1SDimitry Andric   for (const auto &core_range : ranges_32) {
841*0fca6ea1SDimitry Andric     stack_start_addresses.insert(core_range.range.start());
842*0fca6ea1SDimitry Andric     total_size += core_range.range.size();
843*0fca6ea1SDimitry Andric   }
844*0fca6ea1SDimitry Andric 
845*0fca6ea1SDimitry Andric   if (total_size >= UINT32_MAX) {
846*0fca6ea1SDimitry Andric     error.SetErrorStringWithFormat("Unable to write minidump. Stack memory "
847*0fca6ea1SDimitry Andric                                    "exceeds 32b limit. (Num Stacks %zu)",
848*0fca6ea1SDimitry Andric                                    ranges_32.size());
849*0fca6ea1SDimitry Andric     return error;
850*0fca6ea1SDimitry Andric   }
851*0fca6ea1SDimitry Andric 
852*0fca6ea1SDimitry Andric   Process::CoreFileMemoryRanges all_core_memory_ranges;
853*0fca6ea1SDimitry Andric   if (core_style != SaveCoreStyle::eSaveCoreStackOnly) {
854*0fca6ea1SDimitry Andric     error = m_process_sp->CalculateCoreFileSaveRanges(core_style,
855*0fca6ea1SDimitry Andric                                                       all_core_memory_ranges);
856*0fca6ea1SDimitry Andric     if (error.Fail())
857*0fca6ea1SDimitry Andric       return error;
858*0fca6ea1SDimitry Andric   }
859*0fca6ea1SDimitry Andric 
860*0fca6ea1SDimitry Andric   // After saving the stacks, we start packing as much as we can into 32b.
861*0fca6ea1SDimitry Andric   // We apply a generous padding here so that the Directory, MemoryList and
862*0fca6ea1SDimitry Andric   // Memory64List sections all begin in 32b addressable space.
863*0fca6ea1SDimitry Andric   // Then anything overflow extends into 64b addressable space.
864*0fca6ea1SDimitry Andric   // All core memeroy ranges will either container nothing on stacks only
865*0fca6ea1SDimitry Andric   // or all the memory ranges including stacks
866*0fca6ea1SDimitry Andric   if (!all_core_memory_ranges.empty())
867*0fca6ea1SDimitry Andric     total_size +=
868*0fca6ea1SDimitry Andric         256 + (all_core_memory_ranges.size() - stack_start_addresses.size()) *
869*0fca6ea1SDimitry Andric                   sizeof(llvm::minidump::MemoryDescriptor_64);
870*0fca6ea1SDimitry Andric 
871*0fca6ea1SDimitry Andric   for (const auto &core_range : all_core_memory_ranges) {
872*0fca6ea1SDimitry Andric     const addr_t range_size = core_range.range.size();
873*0fca6ea1SDimitry Andric     if (stack_start_addresses.count(core_range.range.start()) > 0)
874*0fca6ea1SDimitry Andric       // Don't double save stacks.
875*0fca6ea1SDimitry Andric       continue;
876*0fca6ea1SDimitry Andric 
877*0fca6ea1SDimitry Andric     if (total_size + range_size < UINT32_MAX) {
878*0fca6ea1SDimitry Andric       ranges_32.push_back(core_range);
879*0fca6ea1SDimitry Andric       total_size += range_size;
880*0fca6ea1SDimitry Andric     } else {
881*0fca6ea1SDimitry Andric       ranges_64.push_back(core_range);
882*0fca6ea1SDimitry Andric     }
883*0fca6ea1SDimitry Andric   }
884*0fca6ea1SDimitry Andric 
885*0fca6ea1SDimitry Andric   error = AddMemoryList_32(ranges_32);
886*0fca6ea1SDimitry Andric   if (error.Fail())
887*0fca6ea1SDimitry Andric     return error;
888*0fca6ea1SDimitry Andric 
889*0fca6ea1SDimitry Andric   // Add the remaining memory as a 64b range.
890*0fca6ea1SDimitry Andric   if (!ranges_64.empty()) {
891*0fca6ea1SDimitry Andric     error = AddMemoryList_64(ranges_64);
892*0fca6ea1SDimitry Andric     if (error.Fail())
893*0fca6ea1SDimitry Andric       return error;
894*0fca6ea1SDimitry Andric   }
895*0fca6ea1SDimitry Andric 
896*0fca6ea1SDimitry Andric   return FixThreadStacks();
897*0fca6ea1SDimitry Andric }
898*0fca6ea1SDimitry Andric 
899*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::DumpHeader() const {
900349cc55cSDimitry Andric   // write header
901349cc55cSDimitry Andric   llvm::minidump::Header header;
902349cc55cSDimitry Andric   header.Signature = static_cast<llvm::support::ulittle32_t>(
903349cc55cSDimitry Andric       llvm::minidump::Header::MagicSignature);
904349cc55cSDimitry Andric   header.Version = static_cast<llvm::support::ulittle32_t>(
905349cc55cSDimitry Andric       llvm::minidump::Header::MagicVersion);
906349cc55cSDimitry Andric   header.NumberOfStreams =
907*0fca6ea1SDimitry Andric       static_cast<llvm::support::ulittle32_t>(m_directories.size());
908*0fca6ea1SDimitry Andric   // We write the directories right after the header.
909349cc55cSDimitry Andric   header.StreamDirectoryRVA =
910*0fca6ea1SDimitry Andric       static_cast<llvm::support::ulittle32_t>(HEADER_SIZE);
911349cc55cSDimitry Andric   header.Checksum = static_cast<llvm::support::ulittle32_t>(
912349cc55cSDimitry Andric       0u), // not used in most of the writers
913349cc55cSDimitry Andric       header.TimeDateStamp =
91404eeddc0SDimitry Andric           static_cast<llvm::support::ulittle32_t>(std::time(nullptr));
915349cc55cSDimitry Andric   header.Flags =
916349cc55cSDimitry Andric       static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag
917349cc55cSDimitry Andric 
918349cc55cSDimitry Andric   Status error;
919349cc55cSDimitry Andric   size_t bytes_written;
920349cc55cSDimitry Andric 
921*0fca6ea1SDimitry Andric   m_core_file->SeekFromStart(0);
922*0fca6ea1SDimitry Andric   bytes_written = HEADER_SIZE;
923*0fca6ea1SDimitry Andric   error = m_core_file->Write(&header, bytes_written);
924*0fca6ea1SDimitry Andric   if (error.Fail() || bytes_written != HEADER_SIZE) {
925*0fca6ea1SDimitry Andric     if (bytes_written != HEADER_SIZE)
926349cc55cSDimitry Andric       error.SetErrorStringWithFormat(
927*0fca6ea1SDimitry Andric           "Unable to write the minidump header (written %zd/%zd)",
928*0fca6ea1SDimitry Andric           bytes_written, HEADER_SIZE);
929*0fca6ea1SDimitry Andric     return error;
930*0fca6ea1SDimitry Andric   }
931349cc55cSDimitry Andric   return error;
932349cc55cSDimitry Andric }
933349cc55cSDimitry Andric 
934*0fca6ea1SDimitry Andric offset_t MinidumpFileBuilder::GetCurrentDataEndOffset() const {
935*0fca6ea1SDimitry Andric   return m_data.GetByteSize() + m_saved_data_size;
936349cc55cSDimitry Andric }
937349cc55cSDimitry Andric 
938*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::DumpDirectories() const {
939*0fca6ea1SDimitry Andric   Status error;
940*0fca6ea1SDimitry Andric   size_t bytes_written;
941*0fca6ea1SDimitry Andric   m_core_file->SeekFromStart(HEADER_SIZE);
942349cc55cSDimitry Andric   for (const Directory &dir : m_directories) {
943*0fca6ea1SDimitry Andric     bytes_written = DIRECTORY_SIZE;
944*0fca6ea1SDimitry Andric     error = m_core_file->Write(&dir, bytes_written);
945*0fca6ea1SDimitry Andric     if (error.Fail() || bytes_written != DIRECTORY_SIZE) {
946*0fca6ea1SDimitry Andric       if (bytes_written != DIRECTORY_SIZE)
947349cc55cSDimitry Andric         error.SetErrorStringWithFormat(
948349cc55cSDimitry Andric             "unable to write the directory (written %zd/%zd)", bytes_written,
949*0fca6ea1SDimitry Andric             DIRECTORY_SIZE);
950349cc55cSDimitry Andric       return error;
951349cc55cSDimitry Andric     }
952349cc55cSDimitry Andric   }
953349cc55cSDimitry Andric 
954349cc55cSDimitry Andric   return error;
955349cc55cSDimitry Andric }
956349cc55cSDimitry Andric 
957*0fca6ea1SDimitry Andric static uint64_t
958*0fca6ea1SDimitry Andric GetLargestRangeSize(const Process::CoreFileMemoryRanges &ranges) {
959*0fca6ea1SDimitry Andric   uint64_t max_size = 0;
960*0fca6ea1SDimitry Andric   for (const auto &core_range : ranges)
961*0fca6ea1SDimitry Andric     max_size = std::max(max_size, core_range.range.size());
962*0fca6ea1SDimitry Andric   return max_size;
963349cc55cSDimitry Andric }
964349cc55cSDimitry Andric 
965*0fca6ea1SDimitry Andric Status
966*0fca6ea1SDimitry Andric MinidumpFileBuilder::AddMemoryList_32(Process::CoreFileMemoryRanges &ranges) {
967*0fca6ea1SDimitry Andric   std::vector<MemoryDescriptor> descriptors;
968*0fca6ea1SDimitry Andric   Status error;
969*0fca6ea1SDimitry Andric   if (ranges.size() == 0)
970*0fca6ea1SDimitry Andric     return error;
971*0fca6ea1SDimitry Andric 
972*0fca6ea1SDimitry Andric   Log *log = GetLog(LLDBLog::Object);
973*0fca6ea1SDimitry Andric   size_t region_index = 0;
974*0fca6ea1SDimitry Andric   auto data_up =
975*0fca6ea1SDimitry Andric       std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0);
976*0fca6ea1SDimitry Andric   for (const auto &core_range : ranges) {
977*0fca6ea1SDimitry Andric     // Take the offset before we write.
978*0fca6ea1SDimitry Andric     const offset_t offset_for_data = GetCurrentDataEndOffset();
979*0fca6ea1SDimitry Andric     const addr_t addr = core_range.range.start();
980*0fca6ea1SDimitry Andric     const addr_t size = core_range.range.size();
981*0fca6ea1SDimitry Andric     const addr_t end = core_range.range.end();
982*0fca6ea1SDimitry Andric 
983*0fca6ea1SDimitry Andric     LLDB_LOGF(log,
984*0fca6ea1SDimitry Andric               "AddMemoryList %zu/%zu reading memory for region "
985*0fca6ea1SDimitry Andric               "(%" PRIx64 " bytes) [%" PRIx64 ", %" PRIx64 ")",
986*0fca6ea1SDimitry Andric               region_index, ranges.size(), size, addr, addr + size);
987*0fca6ea1SDimitry Andric     ++region_index;
988*0fca6ea1SDimitry Andric 
989*0fca6ea1SDimitry Andric     const size_t bytes_read =
990*0fca6ea1SDimitry Andric         m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
991*0fca6ea1SDimitry Andric     if (error.Fail() || bytes_read == 0) {
992*0fca6ea1SDimitry Andric       LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s",
993*0fca6ea1SDimitry Andric                 bytes_read, error.AsCString());
994*0fca6ea1SDimitry Andric       // Just skip sections with errors or zero bytes in 32b mode
995*0fca6ea1SDimitry Andric       continue;
996*0fca6ea1SDimitry Andric     } else if (bytes_read != size) {
997*0fca6ea1SDimitry Andric       LLDB_LOGF(
998*0fca6ea1SDimitry Andric           log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes",
999*0fca6ea1SDimitry Andric           addr, size);
1000*0fca6ea1SDimitry Andric     }
1001*0fca6ea1SDimitry Andric 
1002*0fca6ea1SDimitry Andric     MemoryDescriptor descriptor;
1003*0fca6ea1SDimitry Andric     descriptor.StartOfMemoryRange =
1004*0fca6ea1SDimitry Andric         static_cast<llvm::support::ulittle64_t>(addr);
1005*0fca6ea1SDimitry Andric     descriptor.Memory.DataSize =
1006*0fca6ea1SDimitry Andric         static_cast<llvm::support::ulittle32_t>(bytes_read);
1007*0fca6ea1SDimitry Andric     descriptor.Memory.RVA =
1008*0fca6ea1SDimitry Andric         static_cast<llvm::support::ulittle32_t>(offset_for_data);
1009*0fca6ea1SDimitry Andric     descriptors.push_back(descriptor);
1010*0fca6ea1SDimitry Andric     if (m_thread_by_range_end.count(end) > 0)
1011*0fca6ea1SDimitry Andric       m_thread_by_range_end[end].Stack = descriptor;
1012*0fca6ea1SDimitry Andric 
1013*0fca6ea1SDimitry Andric     // Add the data to the buffer, flush as needed.
1014*0fca6ea1SDimitry Andric     error = AddData(data_up->GetBytes(), bytes_read);
1015*0fca6ea1SDimitry Andric     if (error.Fail())
1016*0fca6ea1SDimitry Andric       return error;
1017*0fca6ea1SDimitry Andric   }
1018*0fca6ea1SDimitry Andric 
1019*0fca6ea1SDimitry Andric   // Add a directory that references this list
1020*0fca6ea1SDimitry Andric   // With a size of the number of ranges as a 32 bit num
1021*0fca6ea1SDimitry Andric   // And then the size of all the ranges
1022*0fca6ea1SDimitry Andric   error = AddDirectory(StreamType::MemoryList,
1023*0fca6ea1SDimitry Andric                        sizeof(llvm::support::ulittle32_t) +
1024*0fca6ea1SDimitry Andric                            descriptors.size() *
1025*0fca6ea1SDimitry Andric                                sizeof(llvm::minidump::MemoryDescriptor));
1026*0fca6ea1SDimitry Andric   if (error.Fail())
1027*0fca6ea1SDimitry Andric     return error;
1028*0fca6ea1SDimitry Andric 
1029*0fca6ea1SDimitry Andric   llvm::support::ulittle32_t memory_ranges_num =
1030*0fca6ea1SDimitry Andric       static_cast<llvm::support::ulittle32_t>(descriptors.size());
1031*0fca6ea1SDimitry Andric   m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t));
1032*0fca6ea1SDimitry Andric   // For 32b we can get away with writing off the descriptors after the data.
1033*0fca6ea1SDimitry Andric   // This means no cleanup loop needed.
1034*0fca6ea1SDimitry Andric   m_data.AppendData(descriptors.data(),
1035*0fca6ea1SDimitry Andric                     descriptors.size() * sizeof(MemoryDescriptor));
1036*0fca6ea1SDimitry Andric 
1037*0fca6ea1SDimitry Andric   return error;
1038*0fca6ea1SDimitry Andric }
1039*0fca6ea1SDimitry Andric 
1040*0fca6ea1SDimitry Andric Status
1041*0fca6ea1SDimitry Andric MinidumpFileBuilder::AddMemoryList_64(Process::CoreFileMemoryRanges &ranges) {
1042*0fca6ea1SDimitry Andric   Status error;
1043*0fca6ea1SDimitry Andric   if (ranges.empty())
1044*0fca6ea1SDimitry Andric     return error;
1045*0fca6ea1SDimitry Andric 
1046*0fca6ea1SDimitry Andric   error = AddDirectory(StreamType::Memory64List,
1047*0fca6ea1SDimitry Andric                        (sizeof(llvm::support::ulittle64_t) * 2) +
1048*0fca6ea1SDimitry Andric                            ranges.size() *
1049*0fca6ea1SDimitry Andric                                sizeof(llvm::minidump::MemoryDescriptor_64));
1050*0fca6ea1SDimitry Andric   if (error.Fail())
1051*0fca6ea1SDimitry Andric     return error;
1052*0fca6ea1SDimitry Andric 
1053*0fca6ea1SDimitry Andric   llvm::support::ulittle64_t memory_ranges_num =
1054*0fca6ea1SDimitry Andric       static_cast<llvm::support::ulittle64_t>(ranges.size());
1055*0fca6ea1SDimitry Andric   m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle64_t));
1056*0fca6ea1SDimitry Andric   // Capture the starting offset for all the descriptors so we can clean them up
1057*0fca6ea1SDimitry Andric   // if needed.
1058*0fca6ea1SDimitry Andric   offset_t starting_offset =
1059*0fca6ea1SDimitry Andric       GetCurrentDataEndOffset() + sizeof(llvm::support::ulittle64_t);
1060*0fca6ea1SDimitry Andric   // The base_rva needs to start after the directories, which is right after
1061*0fca6ea1SDimitry Andric   // this 8 byte variable.
1062*0fca6ea1SDimitry Andric   offset_t base_rva =
1063*0fca6ea1SDimitry Andric       starting_offset +
1064*0fca6ea1SDimitry Andric       (ranges.size() * sizeof(llvm::minidump::MemoryDescriptor_64));
1065*0fca6ea1SDimitry Andric   llvm::support::ulittle64_t memory_ranges_base_rva =
1066*0fca6ea1SDimitry Andric       static_cast<llvm::support::ulittle64_t>(base_rva);
1067*0fca6ea1SDimitry Andric   m_data.AppendData(&memory_ranges_base_rva,
1068*0fca6ea1SDimitry Andric                     sizeof(llvm::support::ulittle64_t));
1069*0fca6ea1SDimitry Andric 
1070*0fca6ea1SDimitry Andric   bool cleanup_required = false;
1071*0fca6ea1SDimitry Andric   std::vector<MemoryDescriptor_64> descriptors;
1072*0fca6ea1SDimitry Andric   // Enumerate the ranges and create the memory descriptors so we can append
1073*0fca6ea1SDimitry Andric   // them first
1074*0fca6ea1SDimitry Andric   for (const auto core_range : ranges) {
1075*0fca6ea1SDimitry Andric     // Add the space required to store the memory descriptor
1076*0fca6ea1SDimitry Andric     MemoryDescriptor_64 memory_desc;
1077*0fca6ea1SDimitry Andric     memory_desc.StartOfMemoryRange =
1078*0fca6ea1SDimitry Andric         static_cast<llvm::support::ulittle64_t>(core_range.range.start());
1079*0fca6ea1SDimitry Andric     memory_desc.DataSize =
1080*0fca6ea1SDimitry Andric         static_cast<llvm::support::ulittle64_t>(core_range.range.size());
1081*0fca6ea1SDimitry Andric     descriptors.push_back(memory_desc);
1082*0fca6ea1SDimitry Andric     // Now write this memory descriptor to the buffer.
1083*0fca6ea1SDimitry Andric     m_data.AppendData(&memory_desc, sizeof(MemoryDescriptor_64));
1084*0fca6ea1SDimitry Andric   }
1085*0fca6ea1SDimitry Andric 
1086*0fca6ea1SDimitry Andric   Log *log = GetLog(LLDBLog::Object);
1087*0fca6ea1SDimitry Andric   size_t region_index = 0;
1088*0fca6ea1SDimitry Andric   auto data_up =
1089*0fca6ea1SDimitry Andric       std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0);
1090*0fca6ea1SDimitry Andric   for (const auto &core_range : ranges) {
1091*0fca6ea1SDimitry Andric     const addr_t addr = core_range.range.start();
1092*0fca6ea1SDimitry Andric     const addr_t size = core_range.range.size();
1093*0fca6ea1SDimitry Andric 
1094*0fca6ea1SDimitry Andric     LLDB_LOGF(log,
1095*0fca6ea1SDimitry Andric               "AddMemoryList_64 %zu/%zu reading memory for region "
1096*0fca6ea1SDimitry Andric               "(%" PRIx64 "bytes) "
1097*0fca6ea1SDimitry Andric               "[%" PRIx64 ", %" PRIx64 ")",
1098*0fca6ea1SDimitry Andric               region_index, ranges.size(), size, addr, addr + size);
1099*0fca6ea1SDimitry Andric     ++region_index;
1100*0fca6ea1SDimitry Andric 
1101*0fca6ea1SDimitry Andric     const size_t bytes_read =
1102*0fca6ea1SDimitry Andric         m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error);
1103*0fca6ea1SDimitry Andric     if (error.Fail()) {
1104*0fca6ea1SDimitry Andric       LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s",
1105*0fca6ea1SDimitry Andric                 bytes_read, error.AsCString());
1106*0fca6ea1SDimitry Andric       error.Clear();
1107*0fca6ea1SDimitry Andric       cleanup_required = true;
1108*0fca6ea1SDimitry Andric       descriptors[region_index].DataSize = 0;
1109*0fca6ea1SDimitry Andric     }
1110*0fca6ea1SDimitry Andric     if (bytes_read != size) {
1111*0fca6ea1SDimitry Andric       LLDB_LOGF(
1112*0fca6ea1SDimitry Andric           log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes",
1113*0fca6ea1SDimitry Andric           addr, size);
1114*0fca6ea1SDimitry Andric       cleanup_required = true;
1115*0fca6ea1SDimitry Andric       descriptors[region_index].DataSize = bytes_read;
1116*0fca6ea1SDimitry Andric     }
1117*0fca6ea1SDimitry Andric 
1118*0fca6ea1SDimitry Andric     // Add the data to the buffer, flush as needed.
1119*0fca6ea1SDimitry Andric     error = AddData(data_up->GetBytes(), bytes_read);
1120*0fca6ea1SDimitry Andric     if (error.Fail())
1121*0fca6ea1SDimitry Andric       return error;
1122*0fca6ea1SDimitry Andric   }
1123*0fca6ea1SDimitry Andric 
1124*0fca6ea1SDimitry Andric   // Early return if there is no cleanup needed.
1125*0fca6ea1SDimitry Andric   if (!cleanup_required) {
1126*0fca6ea1SDimitry Andric     return error;
1127*0fca6ea1SDimitry Andric   } else {
1128*0fca6ea1SDimitry Andric     // Flush to disk we can make the fixes in place.
1129*0fca6ea1SDimitry Andric     FlushBufferToDisk();
1130*0fca6ea1SDimitry Andric     // Fixup the descriptors that were not read correctly.
1131*0fca6ea1SDimitry Andric     m_core_file->SeekFromStart(starting_offset);
1132*0fca6ea1SDimitry Andric     size_t bytes_written = sizeof(MemoryDescriptor_64) * descriptors.size();
1133*0fca6ea1SDimitry Andric     error = m_core_file->Write(descriptors.data(), bytes_written);
1134*0fca6ea1SDimitry Andric     if (error.Fail() ||
1135*0fca6ea1SDimitry Andric         bytes_written != sizeof(MemoryDescriptor_64) * descriptors.size()) {
1136*0fca6ea1SDimitry Andric       error.SetErrorStringWithFormat(
1137*0fca6ea1SDimitry Andric           "unable to write the memory descriptors (written %zd/%zd)",
1138*0fca6ea1SDimitry Andric           bytes_written, sizeof(MemoryDescriptor_64) * descriptors.size());
1139*0fca6ea1SDimitry Andric     }
1140*0fca6ea1SDimitry Andric 
1141*0fca6ea1SDimitry Andric     return error;
1142*0fca6ea1SDimitry Andric   }
1143*0fca6ea1SDimitry Andric }
1144*0fca6ea1SDimitry Andric 
1145*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::AddData(const void *data, uint64_t size) {
1146*0fca6ea1SDimitry Andric   // This should also get chunked, because worst case we copy over a big
1147*0fca6ea1SDimitry Andric   // object / memory range, say 5gb. In that case, we'd have to allocate 10gb
1148*0fca6ea1SDimitry Andric   // 5 gb for the buffer we're copying from, and then 5gb for the buffer we're
1149*0fca6ea1SDimitry Andric   // copying to. Which will be short lived and immedaitely go to disk, the goal
1150*0fca6ea1SDimitry Andric   // here is to limit the number of bytes we need to host in memory at any given
1151*0fca6ea1SDimitry Andric   // time.
1152*0fca6ea1SDimitry Andric   m_data.AppendData(data, size);
1153*0fca6ea1SDimitry Andric   if (m_data.GetByteSize() > MAX_WRITE_CHUNK_SIZE)
1154*0fca6ea1SDimitry Andric     return FlushBufferToDisk();
1155*0fca6ea1SDimitry Andric 
1156*0fca6ea1SDimitry Andric   return Status();
1157*0fca6ea1SDimitry Andric }
1158*0fca6ea1SDimitry Andric 
1159*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::FlushBufferToDisk() {
1160*0fca6ea1SDimitry Andric   Status error;
1161*0fca6ea1SDimitry Andric   // Set the stream to it's end.
1162*0fca6ea1SDimitry Andric   m_core_file->SeekFromStart(m_saved_data_size);
1163*0fca6ea1SDimitry Andric   addr_t starting_size = m_data.GetByteSize();
1164*0fca6ea1SDimitry Andric   addr_t remaining_bytes = starting_size;
1165*0fca6ea1SDimitry Andric   offset_t offset = 0;
1166*0fca6ea1SDimitry Andric 
1167*0fca6ea1SDimitry Andric   while (remaining_bytes > 0) {
1168*0fca6ea1SDimitry Andric     size_t bytes_written = remaining_bytes;
1169*0fca6ea1SDimitry Andric     // We don't care how many bytes we wrote unless we got an error
1170*0fca6ea1SDimitry Andric     // so just decrement the remaining bytes.
1171*0fca6ea1SDimitry Andric     error = m_core_file->Write(m_data.GetBytes() + offset, bytes_written);
1172*0fca6ea1SDimitry Andric     if (error.Fail()) {
1173*0fca6ea1SDimitry Andric       error.SetErrorStringWithFormat(
1174*0fca6ea1SDimitry Andric           "Wrote incorrect number of bytes to minidump file. (written %" PRIx64
1175*0fca6ea1SDimitry Andric           "/%" PRIx64 ")",
1176*0fca6ea1SDimitry Andric           starting_size - remaining_bytes, starting_size);
1177*0fca6ea1SDimitry Andric       return error;
1178*0fca6ea1SDimitry Andric     }
1179*0fca6ea1SDimitry Andric 
1180*0fca6ea1SDimitry Andric     offset += bytes_written;
1181*0fca6ea1SDimitry Andric     remaining_bytes -= bytes_written;
1182*0fca6ea1SDimitry Andric   }
1183*0fca6ea1SDimitry Andric 
1184*0fca6ea1SDimitry Andric   m_saved_data_size += starting_size;
1185*0fca6ea1SDimitry Andric   m_data.Clear();
1186*0fca6ea1SDimitry Andric   return error;
1187*0fca6ea1SDimitry Andric }
1188*0fca6ea1SDimitry Andric 
1189*0fca6ea1SDimitry Andric Status MinidumpFileBuilder::DumpFile() {
1190*0fca6ea1SDimitry Andric   Status error;
1191*0fca6ea1SDimitry Andric   // If anything is left unsaved, dump it.
1192*0fca6ea1SDimitry Andric   error = FlushBufferToDisk();
1193*0fca6ea1SDimitry Andric   if (error.Fail())
1194*0fca6ea1SDimitry Andric     return error;
1195*0fca6ea1SDimitry Andric 
1196*0fca6ea1SDimitry Andric   // Overwrite the header which we filled in earlier.
1197*0fca6ea1SDimitry Andric   error = DumpHeader();
1198*0fca6ea1SDimitry Andric   if (error.Fail())
1199*0fca6ea1SDimitry Andric     return error;
1200*0fca6ea1SDimitry Andric 
1201*0fca6ea1SDimitry Andric   // Overwrite the space saved for directories
1202*0fca6ea1SDimitry Andric   error = DumpDirectories();
1203*0fca6ea1SDimitry Andric   if (error.Fail())
1204*0fca6ea1SDimitry Andric     return error;
1205*0fca6ea1SDimitry Andric 
1206*0fca6ea1SDimitry Andric   return error;
1207349cc55cSDimitry Andric }
1208