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