//===-- MinidumpTypes.cpp ---------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // Project includes #include "MinidumpTypes.h" // Other libraries and framework includes // C includes // C++ includes using namespace lldb_private; using namespace minidump; const MinidumpHeader *MinidumpHeader::Parse(llvm::ArrayRef &data) { const MinidumpHeader *header = nullptr; Status error = consumeObject(data, header); const MinidumpHeaderConstants signature = static_cast( static_cast(header->signature)); const MinidumpHeaderConstants version = static_cast( static_cast(header->version) & 0x0000ffff); // the high 16 bits of the version field are implementation specific if (error.Fail() || signature != MinidumpHeaderConstants::Signature || version != MinidumpHeaderConstants::Version) return nullptr; // TODO check for max number of streams ? // TODO more sanity checks ? return header; } // Minidump string llvm::Optional lldb_private::minidump::parseMinidumpString(llvm::ArrayRef &data) { std::string result; const uint32_t *source_length; Status error = consumeObject(data, source_length); if (error.Fail() || *source_length > data.size() || *source_length % 2 != 0) return llvm::None; auto source_start = reinterpret_cast(data.data()); // source_length is the length of the string in bytes // we need the length of the string in UTF-16 characters/code points (16 bits // per char) // that's why it's divided by 2 const auto source_end = source_start + (*source_length) / 2; // resize to worst case length result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * (*source_length) / 2); auto result_start = reinterpret_cast(&result[0]); const auto result_end = result_start + result.size(); llvm::ConvertUTF16toUTF8(&source_start, source_end, &result_start, result_end, llvm::strictConversion); const auto result_size = std::distance(reinterpret_cast(&result[0]), result_start); result.resize(result_size); // shrink to actual length return result; } // MinidumpThread const MinidumpThread *MinidumpThread::Parse(llvm::ArrayRef &data) { const MinidumpThread *thread = nullptr; Status error = consumeObject(data, thread); if (error.Fail()) return nullptr; return thread; } llvm::ArrayRef MinidumpThread::ParseThreadList(llvm::ArrayRef &data) { const llvm::support::ulittle32_t *thread_count; Status error = consumeObject(data, thread_count); if (error.Fail() || *thread_count * sizeof(MinidumpThread) > data.size()) return {}; return llvm::ArrayRef( reinterpret_cast(data.data()), *thread_count); } // MinidumpSystemInfo const MinidumpSystemInfo * MinidumpSystemInfo::Parse(llvm::ArrayRef &data) { const MinidumpSystemInfo *system_info; Status error = consumeObject(data, system_info); if (error.Fail()) return nullptr; return system_info; } // MinidumpMiscInfo const MinidumpMiscInfo *MinidumpMiscInfo::Parse(llvm::ArrayRef &data) { const MinidumpMiscInfo *misc_info; Status error = consumeObject(data, misc_info); if (error.Fail()) return nullptr; return misc_info; } llvm::Optional MinidumpMiscInfo::GetPid() const { uint32_t pid_flag = static_cast(MinidumpMiscInfoFlags::ProcessID); if (flags1 & pid_flag) return llvm::Optional(process_id); return llvm::None; } // Linux Proc Status // it's stored as an ascii string in the file llvm::Optional LinuxProcStatus::Parse(llvm::ArrayRef &data) { LinuxProcStatus result; result.proc_status = llvm::StringRef(reinterpret_cast(data.data()), data.size()); data = data.drop_front(data.size()); llvm::SmallVector lines; result.proc_status.split(lines, '\n', 42); // /proc/$pid/status has 41 lines, but why not use 42? for (auto line : lines) { if (line.consume_front("Pid:")) { line = line.trim(); if (!line.getAsInteger(10, result.pid)) return result; } } return llvm::None; } lldb::pid_t LinuxProcStatus::GetPid() const { return pid; } // Module stuff const MinidumpModule *MinidumpModule::Parse(llvm::ArrayRef &data) { const MinidumpModule *module = nullptr; Status error = consumeObject(data, module); if (error.Fail()) return nullptr; return module; } llvm::ArrayRef MinidumpModule::ParseModuleList(llvm::ArrayRef &data) { const llvm::support::ulittle32_t *modules_count; Status error = consumeObject(data, modules_count); if (error.Fail() || *modules_count * sizeof(MinidumpModule) > data.size()) return {}; return llvm::ArrayRef( reinterpret_cast(data.data()), *modules_count); } // Exception stuff const MinidumpExceptionStream * MinidumpExceptionStream::Parse(llvm::ArrayRef &data) { const MinidumpExceptionStream *exception_stream = nullptr; Status error = consumeObject(data, exception_stream); if (error.Fail()) return nullptr; return exception_stream; } llvm::ArrayRef MinidumpMemoryDescriptor::ParseMemoryList(llvm::ArrayRef &data) { const llvm::support::ulittle32_t *mem_ranges_count; Status error = consumeObject(data, mem_ranges_count); if (error.Fail() || *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) > data.size()) return {}; return llvm::makeArrayRef( reinterpret_cast(data.data()), *mem_ranges_count); } std::pair, uint64_t> MinidumpMemoryDescriptor64::ParseMemory64List(llvm::ArrayRef &data) { const llvm::support::ulittle64_t *mem_ranges_count; Status error = consumeObject(data, mem_ranges_count); if (error.Fail() || *mem_ranges_count * sizeof(MinidumpMemoryDescriptor64) > data.size()) return {}; const llvm::support::ulittle64_t *base_rva; error = consumeObject(data, base_rva); if (error.Fail()) return {}; return std::make_pair( llvm::makeArrayRef( reinterpret_cast(data.data()), *mem_ranges_count), *base_rva); } std::vector MinidumpMemoryInfo::ParseMemoryInfoList(llvm::ArrayRef &data) { const MinidumpMemoryInfoListHeader *header; Status error = consumeObject(data, header); if (error.Fail() || header->size_of_header < sizeof(MinidumpMemoryInfoListHeader) || header->size_of_entry < sizeof(MinidumpMemoryInfo)) return {}; data = data.drop_front(header->size_of_header - sizeof(MinidumpMemoryInfoListHeader)); if (header->size_of_entry * header->num_of_entries > data.size()) return {}; std::vector result; for (uint64_t i = 0; i < header->num_of_entries; ++i) { result.push_back(reinterpret_cast( data.data() + i * header->size_of_entry)); } return result; }