1349cc55cSDimitry Andric //===-- MinidumpFileBuilder.h ---------------------------------------------===// 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 /// \file 10349cc55cSDimitry Andric /// Structure holding data neccessary for minidump file creation. 11349cc55cSDimitry Andric /// 12349cc55cSDimitry Andric /// The class MinidumpFileWriter is used to hold the data that will eventually 13349cc55cSDimitry Andric /// be dumped to the file. 14349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 15349cc55cSDimitry Andric 16349cc55cSDimitry Andric #ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H 17349cc55cSDimitry Andric #define LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H 18349cc55cSDimitry Andric 19349cc55cSDimitry Andric #include <cstddef> 20*0fca6ea1SDimitry Andric #include <cstdint> 215f757f3fSDimitry Andric #include <map> 22*0fca6ea1SDimitry Andric #include <unordered_map> 23*0fca6ea1SDimitry Andric #include <utility> 24*0fca6ea1SDimitry Andric #include <variant> 25349cc55cSDimitry Andric 26*0fca6ea1SDimitry Andric #include "lldb/Target/Process.h" 27349cc55cSDimitry Andric #include "lldb/Target/Target.h" 28349cc55cSDimitry Andric #include "lldb/Utility/DataBufferHeap.h" 29349cc55cSDimitry Andric #include "lldb/Utility/Status.h" 30*0fca6ea1SDimitry Andric #include "lldb/lldb-forward.h" 31*0fca6ea1SDimitry Andric #include "lldb/lldb-types.h" 32349cc55cSDimitry Andric 33*0fca6ea1SDimitry Andric #include "llvm/BinaryFormat/Minidump.h" 34349cc55cSDimitry Andric #include "llvm/Object/Minidump.h" 35349cc55cSDimitry Andric 36349cc55cSDimitry Andric // Write std::string to minidump in the UTF16 format(with null termination char) 37349cc55cSDimitry Andric // with the size(without null termination char) preceding the UTF16 string. 38349cc55cSDimitry Andric // Empty strings are also printed with zero length and just null termination 39349cc55cSDimitry Andric // char. 40349cc55cSDimitry Andric lldb_private::Status WriteString(const std::string &to_write, 41349cc55cSDimitry Andric lldb_private::DataBufferHeap *buffer); 42349cc55cSDimitry Andric 43349cc55cSDimitry Andric /// \class MinidumpFileBuilder 44349cc55cSDimitry Andric /// Minidump writer for Linux 45349cc55cSDimitry Andric /// 46349cc55cSDimitry Andric /// This class provides a Minidump writer that is able to 47*0fca6ea1SDimitry Andric /// snapshot the current process state. 48*0fca6ea1SDimitry Andric /// 49*0fca6ea1SDimitry Andric /// Minidumps are a Microsoft format for dumping process state. 50*0fca6ea1SDimitry Andric /// This class constructs the minidump on disk starting with 51*0fca6ea1SDimitry Andric /// Headers and Directories are written at the top of the file, 52*0fca6ea1SDimitry Andric /// with the amount of bytes being precalculates before any writing takes place 53*0fca6ea1SDimitry Andric /// Then the smaller data sections are written 54*0fca6ea1SDimitry Andric /// SystemInfo, ModuleList, Misc Info. 55*0fca6ea1SDimitry Andric /// Then Threads are emitted, threads are the first section that needs to be 56*0fca6ea1SDimitry Andric /// 'fixed up' this happens when later we emit the memory stream, we identify if 57*0fca6ea1SDimitry Andric /// that stream is the expected stack, and if so we update the stack with the 58*0fca6ea1SDimitry Andric /// current RVA. Lastly the Memory lists are added. For Memory List, this will 59*0fca6ea1SDimitry Andric /// contain everything that can fit within 4.2gb. MemoryList has it's 60*0fca6ea1SDimitry Andric /// descriptors written at the end so it cannot be allowed to overflow. 61*0fca6ea1SDimitry Andric /// 62*0fca6ea1SDimitry Andric /// Memory64List is a special case where it has to be begin before 4.2gb but can 63*0fca6ea1SDimitry Andric /// expand forever The difference in Memory64List is there are no RVA's and all 64*0fca6ea1SDimitry Andric /// the addresses are figured out by starting at the base RVA, and adding the 65*0fca6ea1SDimitry Andric /// antecedent memory sections. 66*0fca6ea1SDimitry Andric /// 67*0fca6ea1SDimitry Andric /// Because Memory64List can be arbitrarily large, this class has to write 68*0fca6ea1SDimitry Andric /// chunks to disk this means we have to precalculate the descriptors and write 69*0fca6ea1SDimitry Andric /// them first, and if we encounter any error, or are unable to read the same 70*0fca6ea1SDimitry Andric /// number of bytes we have to go back and update them on disk. 71*0fca6ea1SDimitry Andric /// 72*0fca6ea1SDimitry Andric /// And as the last step, after all the directories have been added, we go back 73*0fca6ea1SDimitry Andric /// to the top of the file to fill in the header and the redirectory sections 74*0fca6ea1SDimitry Andric /// that we preallocated. 75349cc55cSDimitry Andric class MinidumpFileBuilder { 76349cc55cSDimitry Andric public: 77*0fca6ea1SDimitry Andric MinidumpFileBuilder(lldb::FileUP &&core_file, 78*0fca6ea1SDimitry Andric const lldb::ProcessSP &process_sp) 79*0fca6ea1SDimitry Andric : m_process_sp(process_sp), m_core_file(std::move(core_file)){}; 80349cc55cSDimitry Andric 81349cc55cSDimitry Andric MinidumpFileBuilder(const MinidumpFileBuilder &) = delete; 82349cc55cSDimitry Andric MinidumpFileBuilder &operator=(const MinidumpFileBuilder &) = delete; 83349cc55cSDimitry Andric 84349cc55cSDimitry Andric MinidumpFileBuilder(MinidumpFileBuilder &&other) = default; 85349cc55cSDimitry Andric MinidumpFileBuilder &operator=(MinidumpFileBuilder &&other) = default; 86349cc55cSDimitry Andric 87349cc55cSDimitry Andric ~MinidumpFileBuilder() = default; 88349cc55cSDimitry Andric 89*0fca6ea1SDimitry Andric // This method only calculates the amount of bytes the header and directories 90*0fca6ea1SDimitry Andric // will take up. It does not write the directories or headers. This function 91*0fca6ea1SDimitry Andric // must be called with a followup to fill in the data. 92*0fca6ea1SDimitry Andric lldb_private::Status AddHeaderAndCalculateDirectories(); 93349cc55cSDimitry Andric // Add SystemInfo stream, used for storing the most basic information 94349cc55cSDimitry Andric // about the system, platform etc... 95*0fca6ea1SDimitry Andric lldb_private::Status AddSystemInfo(); 96349cc55cSDimitry Andric // Add ModuleList stream, containing information about all loaded modules 97349cc55cSDimitry Andric // at the time of saving minidump. 98*0fca6ea1SDimitry Andric lldb_private::Status AddModuleList(); 99349cc55cSDimitry Andric // Add ThreadList stream, containing information about all threads running 100349cc55cSDimitry Andric // at the moment of core saving. Contains information about thread 101349cc55cSDimitry Andric // contexts. 102*0fca6ea1SDimitry Andric lldb_private::Status AddThreadList(); 1035f757f3fSDimitry Andric // Add Exception streams for any threads that stopped with exceptions. 104*0fca6ea1SDimitry Andric lldb_private::Status AddExceptions(); 105349cc55cSDimitry Andric // Add MemoryList stream, containing dumps of important memory segments 106*0fca6ea1SDimitry Andric lldb_private::Status AddMemoryList(lldb::SaveCoreStyle core_style); 107349cc55cSDimitry Andric // Add MiscInfo stream, mainly providing ProcessId 108*0fca6ea1SDimitry Andric lldb_private::Status AddMiscInfo(); 109349cc55cSDimitry Andric // Add informative files about a Linux process 110*0fca6ea1SDimitry Andric lldb_private::Status AddLinuxFileStreams(); 111*0fca6ea1SDimitry Andric 112*0fca6ea1SDimitry Andric // Run cleanup and write all remaining bytes to file 113*0fca6ea1SDimitry Andric lldb_private::Status DumpFile(); 114349cc55cSDimitry Andric 115349cc55cSDimitry Andric private: 116*0fca6ea1SDimitry Andric // Add data to the end of the buffer, if the buffer exceeds the flush level, 117*0fca6ea1SDimitry Andric // trigger a flush. 118*0fca6ea1SDimitry Andric lldb_private::Status AddData(const void *data, uint64_t size); 119*0fca6ea1SDimitry Andric // Add MemoryList stream, containing dumps of important memory segments 120*0fca6ea1SDimitry Andric lldb_private::Status 121*0fca6ea1SDimitry Andric AddMemoryList_64(lldb_private::Process::CoreFileMemoryRanges &ranges); 122*0fca6ea1SDimitry Andric lldb_private::Status 123*0fca6ea1SDimitry Andric AddMemoryList_32(lldb_private::Process::CoreFileMemoryRanges &ranges); 124*0fca6ea1SDimitry Andric // Update the thread list on disk with the newly emitted stack RVAs. 125*0fca6ea1SDimitry Andric lldb_private::Status FixThreadStacks(); 126*0fca6ea1SDimitry Andric lldb_private::Status FlushBufferToDisk(); 127*0fca6ea1SDimitry Andric 128*0fca6ea1SDimitry Andric lldb_private::Status DumpHeader() const; 129*0fca6ea1SDimitry Andric lldb_private::Status DumpDirectories() const; 130349cc55cSDimitry Andric // Add directory of StreamType pointing to the current end of the prepared 131349cc55cSDimitry Andric // file with the specified size. 132*0fca6ea1SDimitry Andric lldb_private::Status AddDirectory(llvm::minidump::StreamType type, 133*0fca6ea1SDimitry Andric uint64_t stream_size); 134*0fca6ea1SDimitry Andric lldb::offset_t GetCurrentDataEndOffset() const; 135*0fca6ea1SDimitry Andric // Stores directories to fill in later 136349cc55cSDimitry Andric std::vector<llvm::minidump::Directory> m_directories; 137*0fca6ea1SDimitry Andric // When we write off the threads for the first time, we need to clean them up 138*0fca6ea1SDimitry Andric // and give them the correct RVA once we write the stack memory list. 139*0fca6ea1SDimitry Andric // We save by the end because we only take from the stack pointer up 140*0fca6ea1SDimitry Andric // So the saved off range base can differ from the memory region the stack 141*0fca6ea1SDimitry Andric // pointer is in. 142*0fca6ea1SDimitry Andric std::unordered_map<lldb::addr_t, llvm::minidump::Thread> 143*0fca6ea1SDimitry Andric m_thread_by_range_end; 144349cc55cSDimitry Andric // Main data buffer consisting of data without the minidump header and 145349cc55cSDimitry Andric // directories 146349cc55cSDimitry Andric lldb_private::DataBufferHeap m_data; 147*0fca6ea1SDimitry Andric lldb::ProcessSP m_process_sp; 148*0fca6ea1SDimitry Andric 149*0fca6ea1SDimitry Andric size_t m_expected_directories = 0; 150*0fca6ea1SDimitry Andric uint64_t m_saved_data_size = 0; 151*0fca6ea1SDimitry Andric lldb::offset_t m_thread_list_start = 0; 152*0fca6ea1SDimitry Andric // We set the max write amount to 128 mb, this is arbitrary 153*0fca6ea1SDimitry Andric // but we want to try to keep the size of m_data small 154*0fca6ea1SDimitry Andric // and we will only exceed a 128 mb buffer if we get a memory region 155*0fca6ea1SDimitry Andric // that is larger than 128 mb. 156*0fca6ea1SDimitry Andric static constexpr size_t MAX_WRITE_CHUNK_SIZE = (1024 * 1024 * 128); 157*0fca6ea1SDimitry Andric 158*0fca6ea1SDimitry Andric static constexpr size_t HEADER_SIZE = sizeof(llvm::minidump::Header); 159*0fca6ea1SDimitry Andric static constexpr size_t DIRECTORY_SIZE = sizeof(llvm::minidump::Directory); 1605f757f3fSDimitry Andric 1615f757f3fSDimitry Andric // More that one place can mention the register thread context locations, 1625f757f3fSDimitry Andric // so when we emit the thread contents, remember where it is so we don't have 1635f757f3fSDimitry Andric // to duplicate it in the exception data. 164*0fca6ea1SDimitry Andric std::unordered_map<lldb::tid_t, llvm::minidump::LocationDescriptor> 165*0fca6ea1SDimitry Andric m_tid_to_reg_ctx; 166*0fca6ea1SDimitry Andric lldb::FileUP m_core_file; 167349cc55cSDimitry Andric }; 168349cc55cSDimitry Andric 169349cc55cSDimitry Andric #endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H 170