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 11*5f757f3fSDimitry 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" 17349cc55cSDimitry Andric #include "lldb/Target/MemoryRegionInfo.h" 18349cc55cSDimitry Andric #include "lldb/Target/Process.h" 19349cc55cSDimitry Andric #include "lldb/Target/RegisterContext.h" 20349cc55cSDimitry Andric #include "lldb/Target/StopInfo.h" 21349cc55cSDimitry Andric #include "lldb/Target/ThreadList.h" 22349cc55cSDimitry Andric #include "lldb/Utility/DataExtractor.h" 23349cc55cSDimitry Andric #include "lldb/Utility/RegisterValue.h" 24349cc55cSDimitry Andric 25349cc55cSDimitry Andric #include "llvm/ADT/StringRef.h" 26349cc55cSDimitry Andric #include "llvm/BinaryFormat/Minidump.h" 27349cc55cSDimitry Andric #include "llvm/Support/ConvertUTF.h" 28349cc55cSDimitry Andric #include "llvm/Support/Error.h" 29349cc55cSDimitry Andric 30349cc55cSDimitry Andric #include "Plugins/Process/minidump/MinidumpTypes.h" 31349cc55cSDimitry Andric 32349cc55cSDimitry Andric #include <cinttypes> 33349cc55cSDimitry Andric 34349cc55cSDimitry Andric using namespace lldb; 35349cc55cSDimitry Andric using namespace lldb_private; 36349cc55cSDimitry Andric using namespace llvm::minidump; 37349cc55cSDimitry Andric 38349cc55cSDimitry Andric void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) { 39349cc55cSDimitry Andric LocationDescriptor loc; 40349cc55cSDimitry Andric loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size); 41349cc55cSDimitry Andric // Stream will begin at the current end of data section 42349cc55cSDimitry Andric loc.RVA = static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); 43349cc55cSDimitry Andric 44349cc55cSDimitry Andric Directory dir; 45349cc55cSDimitry Andric dir.Type = static_cast<llvm::support::little_t<StreamType>>(type); 46349cc55cSDimitry Andric dir.Location = loc; 47349cc55cSDimitry Andric 48349cc55cSDimitry Andric m_directories.push_back(dir); 49349cc55cSDimitry Andric } 50349cc55cSDimitry Andric 51349cc55cSDimitry Andric Status MinidumpFileBuilder::AddSystemInfo(const llvm::Triple &target_triple) { 52349cc55cSDimitry Andric Status error; 53349cc55cSDimitry Andric AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo)); 54349cc55cSDimitry Andric 55349cc55cSDimitry Andric llvm::minidump::ProcessorArchitecture arch; 56349cc55cSDimitry Andric switch (target_triple.getArch()) { 57349cc55cSDimitry Andric case llvm::Triple::ArchType::x86_64: 58349cc55cSDimitry Andric arch = ProcessorArchitecture::AMD64; 59349cc55cSDimitry Andric break; 60349cc55cSDimitry Andric case llvm::Triple::ArchType::x86: 61349cc55cSDimitry Andric arch = ProcessorArchitecture::X86; 62349cc55cSDimitry Andric break; 63349cc55cSDimitry Andric case llvm::Triple::ArchType::arm: 64349cc55cSDimitry Andric arch = ProcessorArchitecture::ARM; 65349cc55cSDimitry Andric break; 66349cc55cSDimitry Andric case llvm::Triple::ArchType::aarch64: 67349cc55cSDimitry Andric arch = ProcessorArchitecture::ARM64; 68349cc55cSDimitry Andric break; 69349cc55cSDimitry Andric case llvm::Triple::ArchType::mips64: 70349cc55cSDimitry Andric case llvm::Triple::ArchType::mips64el: 71349cc55cSDimitry Andric case llvm::Triple::ArchType::mips: 72349cc55cSDimitry Andric case llvm::Triple::ArchType::mipsel: 73349cc55cSDimitry Andric arch = ProcessorArchitecture::MIPS; 74349cc55cSDimitry Andric break; 75349cc55cSDimitry Andric case llvm::Triple::ArchType::ppc64: 76349cc55cSDimitry Andric case llvm::Triple::ArchType::ppc: 77349cc55cSDimitry Andric case llvm::Triple::ArchType::ppc64le: 78349cc55cSDimitry Andric arch = ProcessorArchitecture::PPC; 79349cc55cSDimitry Andric break; 80349cc55cSDimitry Andric default: 81349cc55cSDimitry Andric error.SetErrorStringWithFormat("Architecture %s not supported.", 82349cc55cSDimitry Andric target_triple.getArchName().str().c_str()); 83349cc55cSDimitry Andric return error; 84349cc55cSDimitry Andric }; 85349cc55cSDimitry Andric 86349cc55cSDimitry Andric llvm::support::little_t<OSPlatform> platform_id; 87349cc55cSDimitry Andric switch (target_triple.getOS()) { 88349cc55cSDimitry Andric case llvm::Triple::OSType::Linux: 89349cc55cSDimitry Andric if (target_triple.getEnvironment() == 90349cc55cSDimitry Andric llvm::Triple::EnvironmentType::Android) 91349cc55cSDimitry Andric platform_id = OSPlatform::Android; 92349cc55cSDimitry Andric else 93349cc55cSDimitry Andric platform_id = OSPlatform::Linux; 94349cc55cSDimitry Andric break; 95349cc55cSDimitry Andric case llvm::Triple::OSType::Win32: 96349cc55cSDimitry Andric platform_id = OSPlatform::Win32NT; 97349cc55cSDimitry Andric break; 98349cc55cSDimitry Andric case llvm::Triple::OSType::MacOSX: 99349cc55cSDimitry Andric platform_id = OSPlatform::MacOSX; 100349cc55cSDimitry Andric break; 101349cc55cSDimitry Andric case llvm::Triple::OSType::IOS: 102349cc55cSDimitry Andric platform_id = OSPlatform::IOS; 103349cc55cSDimitry Andric break; 104349cc55cSDimitry Andric default: 105349cc55cSDimitry Andric error.SetErrorStringWithFormat("OS %s not supported.", 106349cc55cSDimitry Andric target_triple.getOSName().str().c_str()); 107349cc55cSDimitry Andric return error; 108349cc55cSDimitry Andric }; 109349cc55cSDimitry Andric 110349cc55cSDimitry Andric llvm::minidump::SystemInfo sys_info; 111349cc55cSDimitry Andric sys_info.ProcessorArch = 112349cc55cSDimitry Andric static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch); 113349cc55cSDimitry Andric // Global offset to beginning of a csd_string in a data section 114349cc55cSDimitry Andric sys_info.CSDVersionRVA = static_cast<llvm::support::ulittle32_t>( 115349cc55cSDimitry Andric GetCurrentDataEndOffset() + sizeof(llvm::minidump::SystemInfo)); 116349cc55cSDimitry Andric sys_info.PlatformId = platform_id; 117349cc55cSDimitry Andric m_data.AppendData(&sys_info, sizeof(llvm::minidump::SystemInfo)); 118349cc55cSDimitry Andric 11904eeddc0SDimitry Andric std::string csd_string; 120349cc55cSDimitry Andric 121349cc55cSDimitry Andric error = WriteString(csd_string, &m_data); 122349cc55cSDimitry Andric if (error.Fail()) { 123349cc55cSDimitry Andric error.SetErrorString("Unable to convert the csd string to UTF16."); 124349cc55cSDimitry Andric return error; 125349cc55cSDimitry Andric } 126349cc55cSDimitry Andric 127349cc55cSDimitry Andric return error; 128349cc55cSDimitry Andric } 129349cc55cSDimitry Andric 130349cc55cSDimitry Andric Status WriteString(const std::string &to_write, 131349cc55cSDimitry Andric lldb_private::DataBufferHeap *buffer) { 132349cc55cSDimitry Andric Status error; 133349cc55cSDimitry Andric // let the StringRef eat also null termination char 134349cc55cSDimitry Andric llvm::StringRef to_write_ref(to_write.c_str(), to_write.size() + 1); 135349cc55cSDimitry Andric llvm::SmallVector<llvm::UTF16, 128> to_write_utf16; 136349cc55cSDimitry Andric 137349cc55cSDimitry Andric bool converted = convertUTF8ToUTF16String(to_write_ref, to_write_utf16); 138349cc55cSDimitry Andric if (!converted) { 139349cc55cSDimitry Andric error.SetErrorStringWithFormat( 140349cc55cSDimitry Andric "Unable to convert the string to UTF16. Failed to convert %s", 141349cc55cSDimitry Andric to_write.c_str()); 142349cc55cSDimitry Andric return error; 143349cc55cSDimitry Andric } 144349cc55cSDimitry Andric 145349cc55cSDimitry Andric // size of the UTF16 string should be written without the null termination 146349cc55cSDimitry Andric // character that is stored in 2 bytes 147349cc55cSDimitry Andric llvm::support::ulittle32_t to_write_size(to_write_utf16.size_in_bytes() - 2); 148349cc55cSDimitry Andric 149349cc55cSDimitry Andric buffer->AppendData(&to_write_size, sizeof(llvm::support::ulittle32_t)); 150349cc55cSDimitry Andric buffer->AppendData(to_write_utf16.data(), to_write_utf16.size_in_bytes()); 151349cc55cSDimitry Andric 152349cc55cSDimitry Andric return error; 153349cc55cSDimitry Andric } 154349cc55cSDimitry Andric 155349cc55cSDimitry Andric llvm::Expected<uint64_t> getModuleFileSize(Target &target, 156349cc55cSDimitry Andric const ModuleSP &mod) { 157349cc55cSDimitry Andric SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection(); 158349cc55cSDimitry Andric uint64_t SizeOfImage = 0; 159349cc55cSDimitry Andric 160349cc55cSDimitry Andric if (!sect_sp) { 161349cc55cSDimitry Andric return llvm::createStringError(std::errc::operation_not_supported, 162349cc55cSDimitry Andric "Couldn't obtain the section information."); 163349cc55cSDimitry Andric } 164349cc55cSDimitry Andric lldb::addr_t sect_addr = sect_sp->GetLoadBaseAddress(&target); 165349cc55cSDimitry Andric // Use memory size since zero fill sections, like ".bss", will be smaller on 166349cc55cSDimitry Andric // disk. 167349cc55cSDimitry Andric lldb::addr_t sect_size = sect_sp->GetByteSize(); 168349cc55cSDimitry Andric // This will usually be zero, but make sure to calculate the BaseOfImage 169349cc55cSDimitry Andric // offset. 170349cc55cSDimitry Andric const lldb::addr_t base_sect_offset = 171349cc55cSDimitry Andric mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target) - 172349cc55cSDimitry Andric sect_addr; 173349cc55cSDimitry Andric SizeOfImage = sect_size - base_sect_offset; 174349cc55cSDimitry Andric lldb::addr_t next_sect_addr = sect_addr + sect_size; 175349cc55cSDimitry Andric Address sect_so_addr; 176349cc55cSDimitry Andric target.ResolveLoadAddress(next_sect_addr, sect_so_addr); 177349cc55cSDimitry Andric lldb::SectionSP next_sect_sp = sect_so_addr.GetSection(); 178349cc55cSDimitry Andric while (next_sect_sp && 179349cc55cSDimitry Andric next_sect_sp->GetLoadBaseAddress(&target) == next_sect_addr) { 180349cc55cSDimitry Andric sect_size = sect_sp->GetByteSize(); 181349cc55cSDimitry Andric SizeOfImage += sect_size; 182349cc55cSDimitry Andric next_sect_addr += sect_size; 183349cc55cSDimitry Andric target.ResolveLoadAddress(next_sect_addr, sect_so_addr); 184349cc55cSDimitry Andric next_sect_sp = sect_so_addr.GetSection(); 185349cc55cSDimitry Andric } 186349cc55cSDimitry Andric 187349cc55cSDimitry Andric return SizeOfImage; 188349cc55cSDimitry Andric } 189349cc55cSDimitry Andric 190349cc55cSDimitry Andric // ModuleList stream consists of a number of modules, followed by an array 191349cc55cSDimitry Andric // of llvm::minidump::Module's structures. Every structure informs about a 192349cc55cSDimitry Andric // single module. Additional data of variable length, such as module's names, 193349cc55cSDimitry Andric // are stored just after the ModuleList stream. The llvm::minidump::Module 194349cc55cSDimitry Andric // structures point to this helper data by global offset. 195349cc55cSDimitry Andric Status MinidumpFileBuilder::AddModuleList(Target &target) { 196349cc55cSDimitry Andric constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module); 197349cc55cSDimitry Andric Status error; 198349cc55cSDimitry Andric 199349cc55cSDimitry Andric const ModuleList &modules = target.GetImages(); 200349cc55cSDimitry Andric llvm::support::ulittle32_t modules_count = 201349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(modules.GetSize()); 202349cc55cSDimitry Andric 203349cc55cSDimitry Andric // This helps us with getting the correct global offset in minidump 204349cc55cSDimitry Andric // file later, when we will be setting up offsets from the 205349cc55cSDimitry Andric // the llvm::minidump::Module's structures into helper data 206349cc55cSDimitry Andric size_t size_before = GetCurrentDataEndOffset(); 207349cc55cSDimitry Andric 208349cc55cSDimitry Andric // This is the size of the main part of the ModuleList stream. 209349cc55cSDimitry Andric // It consists of a module number and corresponding number of 210349cc55cSDimitry Andric // structs describing individual modules 211349cc55cSDimitry Andric size_t module_stream_size = 212349cc55cSDimitry Andric sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size; 213349cc55cSDimitry Andric 214349cc55cSDimitry Andric // Adding directory describing this stream. 215349cc55cSDimitry Andric AddDirectory(StreamType::ModuleList, module_stream_size); 216349cc55cSDimitry Andric 217349cc55cSDimitry Andric m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t)); 218349cc55cSDimitry Andric 219349cc55cSDimitry Andric // Temporary storage for the helper data (of variable length) 220349cc55cSDimitry Andric // as these cannot be dumped to m_data before dumping entire 221349cc55cSDimitry Andric // array of module structures. 222349cc55cSDimitry Andric DataBufferHeap helper_data; 223349cc55cSDimitry Andric 224349cc55cSDimitry Andric for (size_t i = 0; i < modules_count; ++i) { 225349cc55cSDimitry Andric ModuleSP mod = modules.GetModuleAtIndex(i); 226349cc55cSDimitry Andric std::string module_name = mod->GetSpecificationDescription(); 227349cc55cSDimitry Andric auto maybe_mod_size = getModuleFileSize(target, mod); 228349cc55cSDimitry Andric if (!maybe_mod_size) { 229349cc55cSDimitry Andric error.SetErrorStringWithFormat("Unable to get the size of module %s.", 230349cc55cSDimitry Andric module_name.c_str()); 231349cc55cSDimitry Andric return error; 232349cc55cSDimitry Andric } 233349cc55cSDimitry Andric 234349cc55cSDimitry Andric uint64_t mod_size = std::move(*maybe_mod_size); 235349cc55cSDimitry Andric 236349cc55cSDimitry Andric llvm::support::ulittle32_t signature = 237349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>( 238349cc55cSDimitry Andric static_cast<uint32_t>(minidump::CvSignature::ElfBuildId)); 239349cc55cSDimitry Andric auto uuid = mod->GetUUID().GetBytes(); 240349cc55cSDimitry Andric 241349cc55cSDimitry Andric VSFixedFileInfo info; 242349cc55cSDimitry Andric info.Signature = static_cast<llvm::support::ulittle32_t>(0u); 243349cc55cSDimitry Andric info.StructVersion = static_cast<llvm::support::ulittle32_t>(0u); 244349cc55cSDimitry Andric info.FileVersionHigh = static_cast<llvm::support::ulittle32_t>(0u); 245349cc55cSDimitry Andric info.FileVersionLow = static_cast<llvm::support::ulittle32_t>(0u); 246349cc55cSDimitry Andric info.ProductVersionHigh = static_cast<llvm::support::ulittle32_t>(0u); 247349cc55cSDimitry Andric info.ProductVersionLow = static_cast<llvm::support::ulittle32_t>(0u); 248349cc55cSDimitry Andric info.FileFlagsMask = static_cast<llvm::support::ulittle32_t>(0u); 249349cc55cSDimitry Andric info.FileFlags = static_cast<llvm::support::ulittle32_t>(0u); 250349cc55cSDimitry Andric info.FileOS = static_cast<llvm::support::ulittle32_t>(0u); 251349cc55cSDimitry Andric info.FileType = static_cast<llvm::support::ulittle32_t>(0u); 252349cc55cSDimitry Andric info.FileSubtype = static_cast<llvm::support::ulittle32_t>(0u); 253349cc55cSDimitry Andric info.FileDateHigh = static_cast<llvm::support::ulittle32_t>(0u); 254349cc55cSDimitry Andric info.FileDateLow = static_cast<llvm::support::ulittle32_t>(0u); 255349cc55cSDimitry Andric 256349cc55cSDimitry Andric LocationDescriptor ld; 257349cc55cSDimitry Andric ld.DataSize = static_cast<llvm::support::ulittle32_t>(0u); 258349cc55cSDimitry Andric ld.RVA = static_cast<llvm::support::ulittle32_t>(0u); 259349cc55cSDimitry Andric 260349cc55cSDimitry Andric // Setting up LocationDescriptor for uuid string. The global offset into 261349cc55cSDimitry Andric // minidump file is calculated. 262349cc55cSDimitry Andric LocationDescriptor ld_cv; 263349cc55cSDimitry Andric ld_cv.DataSize = static_cast<llvm::support::ulittle32_t>( 264349cc55cSDimitry Andric sizeof(llvm::support::ulittle32_t) + uuid.size()); 265349cc55cSDimitry Andric ld_cv.RVA = static_cast<llvm::support::ulittle32_t>( 266349cc55cSDimitry Andric size_before + module_stream_size + helper_data.GetByteSize()); 267349cc55cSDimitry Andric 268349cc55cSDimitry Andric helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t)); 269349cc55cSDimitry Andric helper_data.AppendData(uuid.begin(), uuid.size()); 270349cc55cSDimitry Andric 271349cc55cSDimitry Andric llvm::minidump::Module m; 272349cc55cSDimitry Andric m.BaseOfImage = static_cast<llvm::support::ulittle64_t>( 273349cc55cSDimitry Andric mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target)); 274349cc55cSDimitry Andric m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size); 275349cc55cSDimitry Andric m.Checksum = static_cast<llvm::support::ulittle32_t>(0); 27604eeddc0SDimitry Andric m.TimeDateStamp = 27704eeddc0SDimitry Andric static_cast<llvm::support::ulittle32_t>(std::time(nullptr)); 278349cc55cSDimitry Andric m.ModuleNameRVA = static_cast<llvm::support::ulittle32_t>( 279349cc55cSDimitry Andric size_before + module_stream_size + helper_data.GetByteSize()); 280349cc55cSDimitry Andric m.VersionInfo = info; 281349cc55cSDimitry Andric m.CvRecord = ld_cv; 282349cc55cSDimitry Andric m.MiscRecord = ld; 283349cc55cSDimitry Andric 284349cc55cSDimitry Andric error = WriteString(module_name, &helper_data); 285349cc55cSDimitry Andric 286349cc55cSDimitry Andric if (error.Fail()) 287349cc55cSDimitry Andric return error; 288349cc55cSDimitry Andric 289349cc55cSDimitry Andric m_data.AppendData(&m, sizeof(llvm::minidump::Module)); 290349cc55cSDimitry Andric } 291349cc55cSDimitry Andric 292349cc55cSDimitry Andric m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize()); 293349cc55cSDimitry Andric return error; 294349cc55cSDimitry Andric } 295349cc55cSDimitry Andric 296349cc55cSDimitry Andric uint16_t read_register_u16_raw(RegisterContext *reg_ctx, 297*5f757f3fSDimitry Andric llvm::StringRef reg_name) { 298349cc55cSDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 299349cc55cSDimitry Andric if (!reg_info) 300349cc55cSDimitry Andric return 0; 301349cc55cSDimitry Andric lldb_private::RegisterValue reg_value; 302349cc55cSDimitry Andric bool success = reg_ctx->ReadRegister(reg_info, reg_value); 303349cc55cSDimitry Andric if (!success) 304349cc55cSDimitry Andric return 0; 305349cc55cSDimitry Andric return reg_value.GetAsUInt16(); 306349cc55cSDimitry Andric } 307349cc55cSDimitry Andric 308349cc55cSDimitry Andric uint32_t read_register_u32_raw(RegisterContext *reg_ctx, 309*5f757f3fSDimitry Andric llvm::StringRef reg_name) { 310349cc55cSDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 311349cc55cSDimitry Andric if (!reg_info) 312349cc55cSDimitry Andric return 0; 313349cc55cSDimitry Andric lldb_private::RegisterValue reg_value; 314349cc55cSDimitry Andric bool success = reg_ctx->ReadRegister(reg_info, reg_value); 315349cc55cSDimitry Andric if (!success) 316349cc55cSDimitry Andric return 0; 317349cc55cSDimitry Andric return reg_value.GetAsUInt32(); 318349cc55cSDimitry Andric } 319349cc55cSDimitry Andric 320349cc55cSDimitry Andric uint64_t read_register_u64_raw(RegisterContext *reg_ctx, 321*5f757f3fSDimitry Andric llvm::StringRef reg_name) { 322349cc55cSDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 323349cc55cSDimitry Andric if (!reg_info) 324349cc55cSDimitry Andric return 0; 325349cc55cSDimitry Andric lldb_private::RegisterValue reg_value; 326349cc55cSDimitry Andric bool success = reg_ctx->ReadRegister(reg_info, reg_value); 327349cc55cSDimitry Andric if (!success) 328349cc55cSDimitry Andric return 0; 329349cc55cSDimitry Andric return reg_value.GetAsUInt64(); 330349cc55cSDimitry Andric } 331349cc55cSDimitry Andric 332349cc55cSDimitry Andric llvm::support::ulittle16_t read_register_u16(RegisterContext *reg_ctx, 333*5f757f3fSDimitry Andric llvm::StringRef reg_name) { 334349cc55cSDimitry Andric return static_cast<llvm::support::ulittle16_t>( 335349cc55cSDimitry Andric read_register_u16_raw(reg_ctx, reg_name)); 336349cc55cSDimitry Andric } 337349cc55cSDimitry Andric 338349cc55cSDimitry Andric llvm::support::ulittle32_t read_register_u32(RegisterContext *reg_ctx, 339*5f757f3fSDimitry Andric llvm::StringRef reg_name) { 340349cc55cSDimitry Andric return static_cast<llvm::support::ulittle32_t>( 341349cc55cSDimitry Andric read_register_u32_raw(reg_ctx, reg_name)); 342349cc55cSDimitry Andric } 343349cc55cSDimitry Andric 344349cc55cSDimitry Andric llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx, 345*5f757f3fSDimitry Andric llvm::StringRef reg_name) { 346349cc55cSDimitry Andric return static_cast<llvm::support::ulittle64_t>( 347349cc55cSDimitry Andric read_register_u64_raw(reg_ctx, reg_name)); 348349cc55cSDimitry Andric } 349349cc55cSDimitry Andric 350*5f757f3fSDimitry Andric void read_register_u128(RegisterContext *reg_ctx, llvm::StringRef reg_name, 351*5f757f3fSDimitry Andric uint8_t *dst) { 352*5f757f3fSDimitry Andric const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name); 353*5f757f3fSDimitry Andric if (reg_info) { 354*5f757f3fSDimitry Andric lldb_private::RegisterValue reg_value; 355*5f757f3fSDimitry Andric if (reg_ctx->ReadRegister(reg_info, reg_value)) { 356*5f757f3fSDimitry Andric Status error; 357*5f757f3fSDimitry Andric uint32_t bytes_copied = reg_value.GetAsMemoryData( 358*5f757f3fSDimitry Andric *reg_info, dst, 16, lldb::ByteOrder::eByteOrderLittle, error); 359*5f757f3fSDimitry Andric if (bytes_copied == 16) 360*5f757f3fSDimitry Andric return; 361*5f757f3fSDimitry Andric } 362*5f757f3fSDimitry Andric } 363*5f757f3fSDimitry Andric // If anything goes wrong, then zero out the register value. 364*5f757f3fSDimitry Andric memset(dst, 0, 16); 365*5f757f3fSDimitry Andric } 366*5f757f3fSDimitry Andric 367349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64 368*5f757f3fSDimitry Andric GetThreadContext_x86_64(RegisterContext *reg_ctx) { 369972a253aSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64 thread_context = {}; 370fcaf7f86SDimitry Andric thread_context.p1_home = {}; 371349cc55cSDimitry Andric thread_context.context_flags = static_cast<uint32_t>( 372349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag | 373349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::Control | 374349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::Segments | 375349cc55cSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64_Flags::Integer); 376349cc55cSDimitry Andric thread_context.rax = read_register_u64(reg_ctx, "rax"); 377349cc55cSDimitry Andric thread_context.rbx = read_register_u64(reg_ctx, "rbx"); 378349cc55cSDimitry Andric thread_context.rcx = read_register_u64(reg_ctx, "rcx"); 379349cc55cSDimitry Andric thread_context.rdx = read_register_u64(reg_ctx, "rdx"); 380349cc55cSDimitry Andric thread_context.rdi = read_register_u64(reg_ctx, "rdi"); 381349cc55cSDimitry Andric thread_context.rsi = read_register_u64(reg_ctx, "rsi"); 382349cc55cSDimitry Andric thread_context.rbp = read_register_u64(reg_ctx, "rbp"); 383349cc55cSDimitry Andric thread_context.rsp = read_register_u64(reg_ctx, "rsp"); 384349cc55cSDimitry Andric thread_context.r8 = read_register_u64(reg_ctx, "r8"); 385349cc55cSDimitry Andric thread_context.r9 = read_register_u64(reg_ctx, "r9"); 386349cc55cSDimitry Andric thread_context.r10 = read_register_u64(reg_ctx, "r10"); 387349cc55cSDimitry Andric thread_context.r11 = read_register_u64(reg_ctx, "r11"); 388349cc55cSDimitry Andric thread_context.r12 = read_register_u64(reg_ctx, "r12"); 389349cc55cSDimitry Andric thread_context.r13 = read_register_u64(reg_ctx, "r13"); 390349cc55cSDimitry Andric thread_context.r14 = read_register_u64(reg_ctx, "r14"); 391349cc55cSDimitry Andric thread_context.r15 = read_register_u64(reg_ctx, "r15"); 392349cc55cSDimitry Andric thread_context.rip = read_register_u64(reg_ctx, "rip"); 393349cc55cSDimitry Andric thread_context.eflags = read_register_u32(reg_ctx, "rflags"); 394349cc55cSDimitry Andric thread_context.cs = read_register_u16(reg_ctx, "cs"); 395349cc55cSDimitry Andric thread_context.fs = read_register_u16(reg_ctx, "fs"); 396349cc55cSDimitry Andric thread_context.gs = read_register_u16(reg_ctx, "gs"); 397349cc55cSDimitry Andric thread_context.ss = read_register_u16(reg_ctx, "ss"); 398349cc55cSDimitry Andric thread_context.ds = read_register_u16(reg_ctx, "ds"); 399349cc55cSDimitry Andric return thread_context; 400349cc55cSDimitry Andric } 401349cc55cSDimitry Andric 402*5f757f3fSDimitry Andric minidump::RegisterContextMinidump_ARM64::Context 403*5f757f3fSDimitry Andric GetThreadContext_ARM64(RegisterContext *reg_ctx) { 404*5f757f3fSDimitry Andric minidump::RegisterContextMinidump_ARM64::Context thread_context = {}; 405*5f757f3fSDimitry Andric thread_context.context_flags = static_cast<uint32_t>( 406*5f757f3fSDimitry Andric minidump::RegisterContextMinidump_ARM64::Flags::ARM64_Flag | 407*5f757f3fSDimitry Andric minidump::RegisterContextMinidump_ARM64::Flags::Integer | 408*5f757f3fSDimitry Andric minidump::RegisterContextMinidump_ARM64::Flags::FloatingPoint); 409*5f757f3fSDimitry Andric char reg_name[16]; 410*5f757f3fSDimitry Andric for (uint32_t i = 0; i < 31; ++i) { 411*5f757f3fSDimitry Andric snprintf(reg_name, sizeof(reg_name), "x%u", i); 412*5f757f3fSDimitry Andric thread_context.x[i] = read_register_u64(reg_ctx, reg_name); 413*5f757f3fSDimitry Andric } 414*5f757f3fSDimitry Andric // Work around a bug in debugserver where "sp" on arm64 doesn't have the alt 415*5f757f3fSDimitry Andric // name set to "x31" 416*5f757f3fSDimitry Andric thread_context.x[31] = read_register_u64(reg_ctx, "sp"); 417*5f757f3fSDimitry Andric thread_context.pc = read_register_u64(reg_ctx, "pc"); 418*5f757f3fSDimitry Andric thread_context.cpsr = read_register_u32(reg_ctx, "cpsr"); 419*5f757f3fSDimitry Andric thread_context.fpsr = read_register_u32(reg_ctx, "fpsr"); 420*5f757f3fSDimitry Andric thread_context.fpcr = read_register_u32(reg_ctx, "fpcr"); 421*5f757f3fSDimitry Andric for (uint32_t i = 0; i < 32; ++i) { 422*5f757f3fSDimitry Andric snprintf(reg_name, sizeof(reg_name), "v%u", i); 423*5f757f3fSDimitry Andric read_register_u128(reg_ctx, reg_name, &thread_context.v[i * 16]); 424*5f757f3fSDimitry Andric } 425*5f757f3fSDimitry Andric return thread_context; 426*5f757f3fSDimitry Andric } 427*5f757f3fSDimitry Andric 428*5f757f3fSDimitry Andric class ArchThreadContexts { 429*5f757f3fSDimitry Andric llvm::Triple::ArchType m_arch; 430*5f757f3fSDimitry Andric union { 431*5f757f3fSDimitry Andric lldb_private::minidump::MinidumpContext_x86_64 x86_64; 432*5f757f3fSDimitry Andric lldb_private::minidump::RegisterContextMinidump_ARM64::Context arm64; 433*5f757f3fSDimitry Andric }; 434*5f757f3fSDimitry Andric 435*5f757f3fSDimitry Andric public: 436*5f757f3fSDimitry Andric ArchThreadContexts(llvm::Triple::ArchType arch) : m_arch(arch) {} 437*5f757f3fSDimitry Andric 438*5f757f3fSDimitry Andric bool prepareRegisterContext(RegisterContext *reg_ctx) { 439*5f757f3fSDimitry Andric switch (m_arch) { 440*5f757f3fSDimitry Andric case llvm::Triple::ArchType::x86_64: 441*5f757f3fSDimitry Andric x86_64 = GetThreadContext_x86_64(reg_ctx); 442*5f757f3fSDimitry Andric return true; 443*5f757f3fSDimitry Andric case llvm::Triple::ArchType::aarch64: 444*5f757f3fSDimitry Andric arm64 = GetThreadContext_ARM64(reg_ctx); 445*5f757f3fSDimitry Andric return true; 446*5f757f3fSDimitry Andric default: 447*5f757f3fSDimitry Andric break; 448*5f757f3fSDimitry Andric } 449*5f757f3fSDimitry Andric return false; 450*5f757f3fSDimitry Andric } 451*5f757f3fSDimitry Andric 452*5f757f3fSDimitry Andric const void *data() const { return &x86_64; } 453*5f757f3fSDimitry Andric 454*5f757f3fSDimitry Andric size_t size() const { 455*5f757f3fSDimitry Andric switch (m_arch) { 456*5f757f3fSDimitry Andric case llvm::Triple::ArchType::x86_64: 457*5f757f3fSDimitry Andric return sizeof(x86_64); 458*5f757f3fSDimitry Andric case llvm::Triple::ArchType::aarch64: 459*5f757f3fSDimitry Andric return sizeof(arm64); 460*5f757f3fSDimitry Andric default: 461*5f757f3fSDimitry Andric break; 462*5f757f3fSDimitry Andric } 463*5f757f3fSDimitry Andric return 0; 464*5f757f3fSDimitry Andric } 465*5f757f3fSDimitry Andric }; 466*5f757f3fSDimitry Andric 467349cc55cSDimitry Andric // Function returns start and size of the memory region that contains 468349cc55cSDimitry Andric // memory location pointed to by the current stack pointer. 469349cc55cSDimitry Andric llvm::Expected<std::pair<addr_t, addr_t>> 470349cc55cSDimitry Andric findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) { 471349cc55cSDimitry Andric MemoryRegionInfo range_info; 472349cc55cSDimitry Andric Status error = process_sp->GetMemoryRegionInfo(rsp, range_info); 473349cc55cSDimitry Andric // Skip failed memory region requests or any regions with no permissions. 474349cc55cSDimitry Andric if (error.Fail() || range_info.GetLLDBPermissions() == 0) 475349cc55cSDimitry Andric return llvm::createStringError( 476349cc55cSDimitry Andric std::errc::not_supported, 477349cc55cSDimitry Andric "unable to load stack segment of the process"); 478349cc55cSDimitry Andric 479349cc55cSDimitry Andric const addr_t addr = range_info.GetRange().GetRangeBase(); 480349cc55cSDimitry Andric const addr_t size = range_info.GetRange().GetByteSize(); 481349cc55cSDimitry Andric 482349cc55cSDimitry Andric if (size == 0) 483349cc55cSDimitry Andric return llvm::createStringError(std::errc::not_supported, 484349cc55cSDimitry Andric "stack segment of the process is empty"); 485349cc55cSDimitry Andric 486349cc55cSDimitry Andric return std::make_pair(addr, size); 487349cc55cSDimitry Andric } 488349cc55cSDimitry Andric 489349cc55cSDimitry Andric Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) { 490349cc55cSDimitry Andric constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread); 491349cc55cSDimitry Andric lldb_private::ThreadList thread_list = process_sp->GetThreadList(); 492349cc55cSDimitry Andric 493349cc55cSDimitry Andric // size of the entire thread stream consists of: 494349cc55cSDimitry Andric // number of threads and threads array 495349cc55cSDimitry Andric size_t thread_stream_size = sizeof(llvm::support::ulittle32_t) + 496349cc55cSDimitry Andric thread_list.GetSize() * minidump_thread_size; 497349cc55cSDimitry Andric // save for the ability to set up RVA 498349cc55cSDimitry Andric size_t size_before = GetCurrentDataEndOffset(); 499349cc55cSDimitry Andric 500349cc55cSDimitry Andric AddDirectory(StreamType::ThreadList, thread_stream_size); 501349cc55cSDimitry Andric 502349cc55cSDimitry Andric llvm::support::ulittle32_t thread_count = 503349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(thread_list.GetSize()); 504349cc55cSDimitry Andric m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t)); 505349cc55cSDimitry Andric 506349cc55cSDimitry Andric DataBufferHeap helper_data; 507349cc55cSDimitry Andric 508349cc55cSDimitry Andric const uint32_t num_threads = thread_list.GetSize(); 509349cc55cSDimitry Andric 510349cc55cSDimitry Andric for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { 511349cc55cSDimitry Andric ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); 512349cc55cSDimitry Andric RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); 513349cc55cSDimitry Andric Status error; 514349cc55cSDimitry Andric 515349cc55cSDimitry Andric if (!reg_ctx_sp) { 516349cc55cSDimitry Andric error.SetErrorString("Unable to get the register context."); 517349cc55cSDimitry Andric return error; 518349cc55cSDimitry Andric } 519349cc55cSDimitry Andric RegisterContext *reg_ctx = reg_ctx_sp.get(); 520*5f757f3fSDimitry Andric Target &target = process_sp->GetTarget(); 521*5f757f3fSDimitry Andric const ArchSpec &arch = target.GetArchitecture(); 522*5f757f3fSDimitry Andric ArchThreadContexts thread_context(arch.GetMachine()); 523*5f757f3fSDimitry Andric if (!thread_context.prepareRegisterContext(reg_ctx)) { 524*5f757f3fSDimitry Andric error.SetErrorStringWithFormat( 525*5f757f3fSDimitry Andric "architecture %s not supported.", 526*5f757f3fSDimitry Andric arch.GetTriple().getArchName().str().c_str()); 527*5f757f3fSDimitry Andric return error; 528*5f757f3fSDimitry Andric } 529*5f757f3fSDimitry Andric uint64_t sp = reg_ctx->GetSP(); 530*5f757f3fSDimitry Andric auto expected_address_range = findStackHelper(process_sp, sp); 531349cc55cSDimitry Andric 532349cc55cSDimitry Andric if (!expected_address_range) { 533*5f757f3fSDimitry Andric consumeError(expected_address_range.takeError()); 534349cc55cSDimitry Andric error.SetErrorString("Unable to get the stack address."); 535349cc55cSDimitry Andric return error; 536349cc55cSDimitry Andric } 537349cc55cSDimitry Andric 538349cc55cSDimitry Andric std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range); 539349cc55cSDimitry Andric uint64_t addr = range.first; 540349cc55cSDimitry Andric uint64_t size = range.second; 541349cc55cSDimitry Andric 542349cc55cSDimitry Andric auto data_up = std::make_unique<DataBufferHeap>(size, 0); 543349cc55cSDimitry Andric const size_t stack_bytes_read = 544349cc55cSDimitry Andric process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); 545349cc55cSDimitry Andric 546349cc55cSDimitry Andric if (error.Fail()) 547349cc55cSDimitry Andric return error; 548349cc55cSDimitry Andric 549349cc55cSDimitry Andric LocationDescriptor stack_memory; 550349cc55cSDimitry Andric stack_memory.DataSize = 551349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(stack_bytes_read); 552349cc55cSDimitry Andric stack_memory.RVA = static_cast<llvm::support::ulittle32_t>( 553349cc55cSDimitry Andric size_before + thread_stream_size + helper_data.GetByteSize()); 554349cc55cSDimitry Andric 555349cc55cSDimitry Andric MemoryDescriptor stack; 556349cc55cSDimitry Andric stack.StartOfMemoryRange = static_cast<llvm::support::ulittle64_t>(addr); 557349cc55cSDimitry Andric stack.Memory = stack_memory; 558349cc55cSDimitry Andric 559349cc55cSDimitry Andric helper_data.AppendData(data_up->GetBytes(), stack_bytes_read); 560349cc55cSDimitry Andric 561349cc55cSDimitry Andric LocationDescriptor thread_context_memory_locator; 562349cc55cSDimitry Andric thread_context_memory_locator.DataSize = 563*5f757f3fSDimitry Andric static_cast<llvm::support::ulittle32_t>(thread_context.size()); 564349cc55cSDimitry Andric thread_context_memory_locator.RVA = static_cast<llvm::support::ulittle32_t>( 565349cc55cSDimitry Andric size_before + thread_stream_size + helper_data.GetByteSize()); 566*5f757f3fSDimitry Andric // Cache thie thread context memory so we can reuse for exceptions. 567*5f757f3fSDimitry Andric m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator; 568349cc55cSDimitry Andric 569*5f757f3fSDimitry Andric helper_data.AppendData(thread_context.data(), thread_context.size()); 570349cc55cSDimitry Andric 571349cc55cSDimitry Andric llvm::minidump::Thread t; 572349cc55cSDimitry Andric t.ThreadId = static_cast<llvm::support::ulittle32_t>(thread_sp->GetID()); 573349cc55cSDimitry Andric t.SuspendCount = static_cast<llvm::support::ulittle32_t>( 574349cc55cSDimitry Andric (thread_sp->GetState() == StateType::eStateSuspended) ? 1 : 0); 575349cc55cSDimitry Andric t.PriorityClass = static_cast<llvm::support::ulittle32_t>(0); 576349cc55cSDimitry Andric t.Priority = static_cast<llvm::support::ulittle32_t>(0); 577349cc55cSDimitry Andric t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0); 578349cc55cSDimitry Andric t.Stack = stack, t.Context = thread_context_memory_locator; 579349cc55cSDimitry Andric 580349cc55cSDimitry Andric m_data.AppendData(&t, sizeof(llvm::minidump::Thread)); 581349cc55cSDimitry Andric } 582349cc55cSDimitry Andric 583349cc55cSDimitry Andric m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize()); 584349cc55cSDimitry Andric return Status(); 585349cc55cSDimitry Andric } 586349cc55cSDimitry Andric 587*5f757f3fSDimitry Andric void MinidumpFileBuilder::AddExceptions(const lldb::ProcessSP &process_sp) { 588349cc55cSDimitry Andric lldb_private::ThreadList thread_list = process_sp->GetThreadList(); 589349cc55cSDimitry Andric 590349cc55cSDimitry Andric const uint32_t num_threads = thread_list.GetSize(); 591*5f757f3fSDimitry Andric for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { 592*5f757f3fSDimitry Andric ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); 593349cc55cSDimitry Andric StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); 594*5f757f3fSDimitry Andric bool add_exception = false; 595*5f757f3fSDimitry Andric if (stop_info_sp) { 596*5f757f3fSDimitry Andric switch (stop_info_sp->GetStopReason()) { 597*5f757f3fSDimitry Andric case eStopReasonSignal: 598*5f757f3fSDimitry Andric case eStopReasonException: 599*5f757f3fSDimitry Andric add_exception = true; 600*5f757f3fSDimitry Andric break; 601*5f757f3fSDimitry Andric default: 602349cc55cSDimitry Andric break; 603349cc55cSDimitry Andric } 604349cc55cSDimitry Andric } 605*5f757f3fSDimitry Andric if (add_exception) { 606349cc55cSDimitry Andric constexpr size_t minidump_exception_size = 607349cc55cSDimitry Andric sizeof(llvm::minidump::ExceptionStream); 608349cc55cSDimitry Andric AddDirectory(StreamType::Exception, minidump_exception_size); 609349cc55cSDimitry Andric StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); 610*5f757f3fSDimitry Andric RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); 611972a253aSDimitry Andric Exception exp_record = {}; 612349cc55cSDimitry Andric exp_record.ExceptionCode = 613349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue()); 614349cc55cSDimitry Andric exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0); 615349cc55cSDimitry Andric exp_record.ExceptionRecord = static_cast<llvm::support::ulittle64_t>(0); 616*5f757f3fSDimitry Andric exp_record.ExceptionAddress = reg_ctx_sp->GetPC(); 617349cc55cSDimitry Andric exp_record.NumberParameters = static_cast<llvm::support::ulittle32_t>(0); 618349cc55cSDimitry Andric exp_record.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); 619349cc55cSDimitry Andric // exp_record.ExceptionInformation; 620349cc55cSDimitry Andric 621349cc55cSDimitry Andric ExceptionStream exp_stream; 622349cc55cSDimitry Andric exp_stream.ThreadId = 623349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(thread_sp->GetID()); 624349cc55cSDimitry Andric exp_stream.UnusedAlignment = static_cast<llvm::support::ulittle32_t>(0); 625349cc55cSDimitry Andric exp_stream.ExceptionRecord = exp_record; 626*5f757f3fSDimitry Andric auto Iter = m_tid_to_reg_ctx.find(thread_sp->GetID()); 627*5f757f3fSDimitry Andric if (Iter != m_tid_to_reg_ctx.end()) { 628*5f757f3fSDimitry Andric exp_stream.ThreadContext = Iter->second; 629*5f757f3fSDimitry Andric } else { 630*5f757f3fSDimitry Andric exp_stream.ThreadContext.DataSize = 0; 631*5f757f3fSDimitry Andric exp_stream.ThreadContext.RVA = 0; 632*5f757f3fSDimitry Andric } 633349cc55cSDimitry Andric m_data.AppendData(&exp_stream, minidump_exception_size); 634*5f757f3fSDimitry Andric } 635*5f757f3fSDimitry Andric } 636349cc55cSDimitry Andric } 637349cc55cSDimitry Andric 638349cc55cSDimitry Andric lldb_private::Status 639*5f757f3fSDimitry Andric MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp, 640*5f757f3fSDimitry Andric lldb::SaveCoreStyle core_style) { 641349cc55cSDimitry Andric Status error; 642*5f757f3fSDimitry Andric Process::CoreFileMemoryRanges core_ranges; 643*5f757f3fSDimitry Andric error = process_sp->CalculateCoreFileSaveRanges(core_style, core_ranges); 644349cc55cSDimitry Andric if (error.Fail()) { 645349cc55cSDimitry Andric error.SetErrorString("Process doesn't support getting memory region info."); 646349cc55cSDimitry Andric return error; 647349cc55cSDimitry Andric } 648349cc55cSDimitry Andric 649349cc55cSDimitry Andric DataBufferHeap helper_data; 650349cc55cSDimitry Andric std::vector<MemoryDescriptor> mem_descriptors; 651*5f757f3fSDimitry Andric for (const auto &core_range : core_ranges) { 652*5f757f3fSDimitry Andric // Skip empty memory regions or any regions with no permissions. 653*5f757f3fSDimitry Andric if (core_range.range.empty() || core_range.lldb_permissions == 0) 654349cc55cSDimitry Andric continue; 655*5f757f3fSDimitry Andric const addr_t addr = core_range.range.start(); 656*5f757f3fSDimitry Andric const addr_t size = core_range.range.size(); 657349cc55cSDimitry Andric auto data_up = std::make_unique<DataBufferHeap>(size, 0); 658349cc55cSDimitry Andric const size_t bytes_read = 659349cc55cSDimitry Andric process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); 660349cc55cSDimitry Andric if (bytes_read == 0) 661349cc55cSDimitry Andric continue; 662349cc55cSDimitry Andric // We have a good memory region with valid bytes to store. 663349cc55cSDimitry Andric LocationDescriptor memory_dump; 664349cc55cSDimitry Andric memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(bytes_read); 665349cc55cSDimitry Andric memory_dump.RVA = 666349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); 667349cc55cSDimitry Andric MemoryDescriptor memory_desc; 668349cc55cSDimitry Andric memory_desc.StartOfMemoryRange = 669349cc55cSDimitry Andric static_cast<llvm::support::ulittle64_t>(addr); 670349cc55cSDimitry Andric memory_desc.Memory = memory_dump; 671349cc55cSDimitry Andric mem_descriptors.push_back(memory_desc); 672349cc55cSDimitry Andric m_data.AppendData(data_up->GetBytes(), bytes_read); 673349cc55cSDimitry Andric } 674349cc55cSDimitry Andric 675349cc55cSDimitry Andric AddDirectory(StreamType::MemoryList, 676349cc55cSDimitry Andric sizeof(llvm::support::ulittle32_t) + 677349cc55cSDimitry Andric mem_descriptors.size() * 678349cc55cSDimitry Andric sizeof(llvm::minidump::MemoryDescriptor)); 679349cc55cSDimitry Andric llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size()); 680349cc55cSDimitry Andric 681349cc55cSDimitry Andric m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t)); 682349cc55cSDimitry Andric for (auto memory_descriptor : mem_descriptors) { 683349cc55cSDimitry Andric m_data.AppendData(&memory_descriptor, 684349cc55cSDimitry Andric sizeof(llvm::minidump::MemoryDescriptor)); 685349cc55cSDimitry Andric } 686349cc55cSDimitry Andric 687349cc55cSDimitry Andric return error; 688349cc55cSDimitry Andric } 689349cc55cSDimitry Andric 690349cc55cSDimitry Andric void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) { 691349cc55cSDimitry Andric AddDirectory(StreamType::MiscInfo, 692349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpMiscInfo)); 693349cc55cSDimitry Andric 694349cc55cSDimitry Andric lldb_private::minidump::MinidumpMiscInfo misc_info; 695349cc55cSDimitry Andric misc_info.size = static_cast<llvm::support::ulittle32_t>( 696349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpMiscInfo)); 697349cc55cSDimitry Andric // Default set flags1 to 0, in case that we will not be able to 698349cc55cSDimitry Andric // get any information 699349cc55cSDimitry Andric misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0); 700349cc55cSDimitry Andric 701349cc55cSDimitry Andric lldb_private::ProcessInstanceInfo process_info; 702349cc55cSDimitry Andric process_sp->GetProcessInfo(process_info); 703349cc55cSDimitry Andric if (process_info.ProcessIDIsValid()) { 704349cc55cSDimitry Andric // Set flags1 to reflect that PID is filled in 705349cc55cSDimitry Andric misc_info.flags1 = 706349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(static_cast<uint32_t>( 707349cc55cSDimitry Andric lldb_private::minidump::MinidumpMiscInfoFlags::ProcessID)); 708349cc55cSDimitry Andric misc_info.process_id = 709349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(process_info.GetProcessID()); 710349cc55cSDimitry Andric } 711349cc55cSDimitry Andric 712349cc55cSDimitry Andric m_data.AppendData(&misc_info, 713349cc55cSDimitry Andric sizeof(lldb_private::minidump::MinidumpMiscInfo)); 714349cc55cSDimitry Andric } 715349cc55cSDimitry Andric 716349cc55cSDimitry Andric std::unique_ptr<llvm::MemoryBuffer> 717349cc55cSDimitry Andric getFileStreamHelper(const std::string &path) { 718349cc55cSDimitry Andric auto maybe_stream = llvm::MemoryBuffer::getFileAsStream(path); 719349cc55cSDimitry Andric if (!maybe_stream) 720349cc55cSDimitry Andric return nullptr; 721349cc55cSDimitry Andric return std::move(maybe_stream.get()); 722349cc55cSDimitry Andric } 723349cc55cSDimitry Andric 724349cc55cSDimitry Andric void MinidumpFileBuilder::AddLinuxFileStreams( 725349cc55cSDimitry Andric const lldb::ProcessSP &process_sp) { 726349cc55cSDimitry Andric std::vector<std::pair<StreamType, std::string>> files_with_stream_types = { 727349cc55cSDimitry Andric {StreamType::LinuxCPUInfo, "/proc/cpuinfo"}, 728349cc55cSDimitry Andric {StreamType::LinuxLSBRelease, "/etc/lsb-release"}, 729349cc55cSDimitry Andric }; 730349cc55cSDimitry Andric 731349cc55cSDimitry Andric lldb_private::ProcessInstanceInfo process_info; 732349cc55cSDimitry Andric process_sp->GetProcessInfo(process_info); 733349cc55cSDimitry Andric if (process_info.ProcessIDIsValid()) { 734349cc55cSDimitry Andric lldb::pid_t pid = process_info.GetProcessID(); 735349cc55cSDimitry Andric std::string pid_str = std::to_string(pid); 736349cc55cSDimitry Andric files_with_stream_types.push_back( 737349cc55cSDimitry Andric {StreamType::LinuxProcStatus, "/proc/" + pid_str + "/status"}); 738349cc55cSDimitry Andric files_with_stream_types.push_back( 739349cc55cSDimitry Andric {StreamType::LinuxCMDLine, "/proc/" + pid_str + "/cmdline"}); 740349cc55cSDimitry Andric files_with_stream_types.push_back( 741349cc55cSDimitry Andric {StreamType::LinuxEnviron, "/proc/" + pid_str + "/environ"}); 742349cc55cSDimitry Andric files_with_stream_types.push_back( 743349cc55cSDimitry Andric {StreamType::LinuxAuxv, "/proc/" + pid_str + "/auxv"}); 744349cc55cSDimitry Andric files_with_stream_types.push_back( 745349cc55cSDimitry Andric {StreamType::LinuxMaps, "/proc/" + pid_str + "/maps"}); 746349cc55cSDimitry Andric files_with_stream_types.push_back( 747349cc55cSDimitry Andric {StreamType::LinuxProcStat, "/proc/" + pid_str + "/stat"}); 748349cc55cSDimitry Andric files_with_stream_types.push_back( 749349cc55cSDimitry Andric {StreamType::LinuxProcFD, "/proc/" + pid_str + "/fd"}); 750349cc55cSDimitry Andric } 751349cc55cSDimitry Andric 752349cc55cSDimitry Andric for (const auto &entry : files_with_stream_types) { 753349cc55cSDimitry Andric StreamType stream = entry.first; 754349cc55cSDimitry Andric std::string path = entry.second; 755349cc55cSDimitry Andric auto memory_buffer = getFileStreamHelper(path); 756349cc55cSDimitry Andric 757349cc55cSDimitry Andric if (memory_buffer) { 758349cc55cSDimitry Andric size_t size = memory_buffer->getBufferSize(); 759349cc55cSDimitry Andric if (size == 0) 760349cc55cSDimitry Andric continue; 761349cc55cSDimitry Andric AddDirectory(stream, size); 762349cc55cSDimitry Andric m_data.AppendData(memory_buffer->getBufferStart(), size); 763349cc55cSDimitry Andric } 764349cc55cSDimitry Andric } 765349cc55cSDimitry Andric } 766349cc55cSDimitry Andric 767349cc55cSDimitry Andric Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const { 768349cc55cSDimitry Andric constexpr size_t header_size = sizeof(llvm::minidump::Header); 769349cc55cSDimitry Andric constexpr size_t directory_size = sizeof(llvm::minidump::Directory); 770349cc55cSDimitry Andric 771349cc55cSDimitry Andric // write header 772349cc55cSDimitry Andric llvm::minidump::Header header; 773349cc55cSDimitry Andric header.Signature = static_cast<llvm::support::ulittle32_t>( 774349cc55cSDimitry Andric llvm::minidump::Header::MagicSignature); 775349cc55cSDimitry Andric header.Version = static_cast<llvm::support::ulittle32_t>( 776349cc55cSDimitry Andric llvm::minidump::Header::MagicVersion); 777349cc55cSDimitry Andric header.NumberOfStreams = 778349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(GetDirectoriesNum()); 779349cc55cSDimitry Andric header.StreamDirectoryRVA = 780349cc55cSDimitry Andric static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); 781349cc55cSDimitry Andric header.Checksum = static_cast<llvm::support::ulittle32_t>( 782349cc55cSDimitry Andric 0u), // not used in most of the writers 783349cc55cSDimitry Andric header.TimeDateStamp = 78404eeddc0SDimitry Andric static_cast<llvm::support::ulittle32_t>(std::time(nullptr)); 785349cc55cSDimitry Andric header.Flags = 786349cc55cSDimitry Andric static_cast<llvm::support::ulittle64_t>(0u); // minidump normal flag 787349cc55cSDimitry Andric 788349cc55cSDimitry Andric Status error; 789349cc55cSDimitry Andric size_t bytes_written; 790349cc55cSDimitry Andric 791349cc55cSDimitry Andric bytes_written = header_size; 792349cc55cSDimitry Andric error = core_file->Write(&header, bytes_written); 793349cc55cSDimitry Andric if (error.Fail() || bytes_written != header_size) { 794349cc55cSDimitry Andric if (bytes_written != header_size) 795349cc55cSDimitry Andric error.SetErrorStringWithFormat( 796349cc55cSDimitry Andric "unable to write the header (written %zd/%zd)", bytes_written, 797349cc55cSDimitry Andric header_size); 798349cc55cSDimitry Andric return error; 799349cc55cSDimitry Andric } 800349cc55cSDimitry Andric 801349cc55cSDimitry Andric // write data 802349cc55cSDimitry Andric bytes_written = m_data.GetByteSize(); 803349cc55cSDimitry Andric error = core_file->Write(m_data.GetBytes(), bytes_written); 804349cc55cSDimitry Andric if (error.Fail() || bytes_written != m_data.GetByteSize()) { 805349cc55cSDimitry Andric if (bytes_written != m_data.GetByteSize()) 806349cc55cSDimitry Andric error.SetErrorStringWithFormat( 807349cc55cSDimitry Andric "unable to write the data (written %zd/%" PRIu64 ")", bytes_written, 808349cc55cSDimitry Andric m_data.GetByteSize()); 809349cc55cSDimitry Andric return error; 810349cc55cSDimitry Andric } 811349cc55cSDimitry Andric 812349cc55cSDimitry Andric // write directories 813349cc55cSDimitry Andric for (const Directory &dir : m_directories) { 814349cc55cSDimitry Andric bytes_written = directory_size; 815349cc55cSDimitry Andric error = core_file->Write(&dir, bytes_written); 816349cc55cSDimitry Andric if (error.Fail() || bytes_written != directory_size) { 817349cc55cSDimitry Andric if (bytes_written != directory_size) 818349cc55cSDimitry Andric error.SetErrorStringWithFormat( 819349cc55cSDimitry Andric "unable to write the directory (written %zd/%zd)", bytes_written, 820349cc55cSDimitry Andric directory_size); 821349cc55cSDimitry Andric return error; 822349cc55cSDimitry Andric } 823349cc55cSDimitry Andric } 824349cc55cSDimitry Andric 825349cc55cSDimitry Andric return error; 826349cc55cSDimitry Andric } 827349cc55cSDimitry Andric 828349cc55cSDimitry Andric size_t MinidumpFileBuilder::GetDirectoriesNum() const { 829349cc55cSDimitry Andric return m_directories.size(); 830349cc55cSDimitry Andric } 831349cc55cSDimitry Andric 832349cc55cSDimitry Andric size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const { 833349cc55cSDimitry Andric return sizeof(llvm::minidump::Header) + m_data.GetByteSize(); 834349cc55cSDimitry Andric } 835