Add ability to dump minicore 24/208624/5
authorMateusz Moscicki <m.moscicki2@partner.samsung.com>
Wed, 26 Jun 2019 08:49:48 +0000 (10:49 +0200)
committerMateusz Moscicki <m.moscicki2@partner.samsung.com>
Fri, 5 Jul 2019 14:06:26 +0000 (16:06 +0200)
Change-Id: I9056c6e630e11a9990933832906302e45905dea2

12 files changed:
LICENSE.BSD [new file with mode: 0644]
packaging/crash-worker.spec
src/livedumper/CMakeLists.txt
src/livedumper/core.hpp
src/livedumper/helpers.hpp
src/livedumper/livedumper.hpp
src/livedumper/log.hpp
src/livedumper/main.cpp
src/livedumper/maps.hpp
src/livedumper/note.hpp
src/livedumper/prochandle.hpp [new file with mode: 0644]
src/livedumper/program.hpp

diff --git a/LICENSE.BSD b/LICENSE.BSD
new file mode 100644 (file)
index 0000000..5bfb5a0
--- /dev/null
@@ -0,0 +1,20 @@
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+   this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
index 253d84c..5951257 100644 (file)
@@ -192,7 +192,7 @@ sed -i "/${pattern}/D" %{_sysconfdir}/ld.so.preload
 %endif
 
 %files
-%license LICENSE
+%license LICENSE LICENSE.BSD
 %manifest crash-worker.manifest
 %defattr(-,system_fw,system_fw,-)
 %dir %{crash_root_path}
index 27faf24..ea20fc6 100644 (file)
@@ -18,6 +18,7 @@ endif(DLOG)
 
 set(LIVEDUMPER_SRCS main.cpp ${LOGGER_FILE})
 add_executable(${LIVEDUMPER_BIN} ${LIVEDUMPER_SRCS})
+target_link_libraries(${LIVEDUMPER_BIN} -lelf -lthread_db)
 
 if("${LOGGER}" STREQUAL "dlog")
        include(FindPkgConfig)
index d9abfe9..193577c 100644 (file)
@@ -5,7 +5,7 @@
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
 #include "program.hpp"
 
 #include <fcntl.h>
+#include <gelf.h>
 #include <libelf.h>
 #include <limits.h>
+#include <link.h>
 #include <sys/procfs.h>
 
+extern "C" {
+#include <thread_db.h>
+}
+
 #include <cstring>
 #include <iostream>
+#include <map>
 #include <memory>
 #include <string>
 #include <vector>
 
+static constexpr size_t PAGESIZE = 0x1000;
 
 template <typename T>
 class Core {
  private:
-       static constexpr size_t PAGESIZE = 0x1000;
        ProgramTableEntryBase<T> *m_note_header;
        std::vector<std::unique_ptr<ProgramTableEntryBase<T>>> m_phdrt;
+       std::vector<std::unique_ptr<SymData>> m_symdata;
        size_t current_data_address;
        std::vector <std::unique_ptr<Note>> m_notes;
        typename T::Ehdr m_ehdr;
 
  public:
        Core() : m_note_header(new ProgramTableEntryNote<T>()),
-                current_data_address(sizeof(m_ehdr)) {
-               m_phdrt.push_back(std::unique_ptr<ProgramTableEntryBase<T>>(m_note_header));
+                current_data_address(sizeof(m_ehdr)),
+                m_ehdr() {
+                m_phdrt.push_back(std::unique_ptr<ProgramTableEntryBase<T>>(m_note_header));
        }
 
        void FillELFHeader() {
@@ -84,6 +93,7 @@ class Core {
                entry->header.p_filesz = record->end - record->start;
                entry->header.p_memsz = record->end - record->start;
                entry->header.p_align = PAGESIZE;
+               entry->important = record->important;
                m_phdrt.push_back(std::unique_ptr<ProgramTableEntryLoad<T>>(entry));
        }
 
@@ -146,19 +156,17 @@ class Core {
                }
        }
 
-       void SaveLoadable(const std::string &mem_path, std::ofstream &core_file) {
-               int fd = open(mem_path.c_str(), O_RDONLY);
-               if (fd == -1)
-                       throw std::system_error(errno, std::system_category(), "failed to open mem file " + mem_path);
-
+       void SaveLoadable(int mem_fd, std::ofstream &core_file, bool minicore) {
                for (const auto &record : m_phdrt) {
                        if (record->header.p_type != PT_LOAD)
                                continue;
-                       if (lseek64(fd, record->header.p_vaddr, SEEK_SET) == -1)
+                       if (lseek64(mem_fd, record->header.p_vaddr, SEEK_SET) == -1)
                                logger.log_error("lseek64 error: %s", std::system_category().default_error_condition(errno).message());
-                       CopyData(fd, core_file, record->header.p_filesz);
+                       if (!minicore || static_cast<ProgramTableEntryLoad<T>*>(record.get())->important)
+                               CopyData(mem_fd, core_file, record->header.p_filesz);
+                       else
+                               core_file.seekp(record->header.p_filesz, std::ios_base::cur);
                }
-               close(fd);
        }
 
        void AddNote(Note *note) {
@@ -194,6 +202,287 @@ class Core {
                for (const auto &record : records)
                        ImportMapRecord(record);
        }
-};
 
-#endif  // CORE_HPP__
+       typename T::uint AUXVval(const typename T::auxv_t *auxv, typename T::Addr type) {
+               for (int i = 0; auxv[i].a_type != AT_NULL; i++) {
+                       if (auxv[i].a_type == type)
+                               return auxv[i].a_un.a_val;
+               }
+               return 0;
+       }
+
+       void ReadFromFile(std::ifstream &input, unsigned long address, void *data, size_t len) {
+               input.seekg(address, std::ios_base::beg);
+               input.read(static_cast<char*>(data), len);
+       }
+
+       void ReadFromFile(const int fd, unsigned long address, void *data, size_t len) {
+               lseek64(fd, address, SEEK_SET);
+               if (read(fd, data, len) == -1)
+                       throw std::system_error(errno, std::system_category(), "failed to read at " + std::to_string(address));
+       }
+
+       void DumpData(int fd, std::ofstream &output, typename T::Addr iaddress, typename T::Addr oaddress, size_t len, const std::string &desc) {
+               lseek64(fd, iaddress, SEEK_SET);
+               output.seekp(oaddress, std::ios_base::beg);
+               logger.log_info("dumping %s: 0x%x-0x%x to 0x%x (%d bytes)", desc.c_str(), iaddress, iaddress+len, oaddress, len);
+               CopyData(fd, output, len);
+       }
+
+       void DumpData(int fd, std::ofstream &output, typename T::Addr iaddress, size_t len, const std::string &desc) {
+               typename T::Addr out_addr = MemAddr2FileAddr(iaddress);
+               if (out_addr)
+                       DumpData(fd, output, iaddress, out_addr, len, desc);
+               else
+                       logger.log_error("No address for 0x%x", iaddress);
+       }
+
+       ProgramTableEntryLoad<T>* FindRecordForMemAddress(typename T::Addr address) {
+               for (auto &record : m_phdrt) {
+                       if (record->header.p_type != PT_LOAD)
+                               continue;
+
+                       ProgramTableEntryLoad<T>* entry = static_cast<ProgramTableEntryLoad<T>*>(record.get());
+                       if (address >= entry->header.p_vaddr && address < entry->header.p_vaddr + entry->header.p_memsz) {
+                               return entry;
+                       }
+               }
+               return nullptr;
+       }
+
+       typename T::Addr MemAddr2FileAddr(typename T::Addr address) {
+               ProgramTableEntryLoad<T> *record = FindRecordForMemAddress(address);
+
+               if (record == nullptr)
+                       return 0;
+
+               return record->header.p_offset + (address - record->header.p_vaddr);
+       }
+
+       SymData* AllocSymData(const std::string &lib, unsigned long start, typename T::Word type) {
+               elf_version(EV_CURRENT);
+               auto sym_data = new SymData();
+               Elf_Scn *scn = nullptr;
+
+               sym_data->start = start;
+               sym_data->fd = open(lib.c_str(), O_RDONLY);
+
+               if (sym_data->fd < 0) {
+                       delete sym_data;
+                       return nullptr;
+               }
+
+               sym_data->elf = elf_begin(sym_data->fd, ELF_C_READ, nullptr);
+
+               while (1) {
+                       GElf_Shdr *shdr;
+                       scn = elf_nextscn(sym_data->elf, scn);
+
+                       if (!scn) {
+                               elf_end(sym_data->elf);
+                               close(sym_data->fd);
+                               delete sym_data;
+                               logger.log_info("no sym data for %s", lib.c_str());
+                               return nullptr;
+                       }
+
+                       shdr = gelf_getshdr(scn, &sym_data->shdr);
+                       if (shdr && sym_data->shdr.sh_type == type)
+                               break;
+               }
+
+               sym_data->data = elf_getdata(scn, nullptr);
+               sym_data->count = sym_data->shdr.sh_size / sym_data->shdr.sh_entsize;
+
+               return sym_data;
+       }
+
+       void SaveSymData(const std::string &lib, unsigned long start) {
+               SymData* sym_data;
+
+               for (auto type: {SHT_SYMTAB, SHT_DYNSYM}) {
+                       sym_data = AllocSymData(lib, start, type);
+                       if (!sym_data)
+                               continue;
+
+                       m_symdata.push_back(std::unique_ptr<SymData>(sym_data));
+               }
+       }
+
+       static int FindPthreadsCb(const td_thrhandle_t *th, void *cb_data) {
+               td_thrinfo_t thinfo;
+               td_thr_get_info(th, &thinfo);
+               return TD_OK;
+       }
+
+       void SavePthreadList(int mem_fd, std::ofstream &core_file, int pid) {
+               struct ps_prochandle ph = {
+                       .core_obj = this,
+                       .bit32 = (std::is_same<T, Elf32>::value),
+                       .mem_fd = mem_fd,
+                       .core_file = core_file,
+                       .pid = pid
+               };
+
+               td_thragent_t *ta;
+               td_err_e err;
+
+               err = td_ta_new(&ph, &ta);
+               if (err == TD_OK) {
+                       err = td_ta_thr_iter(ta, FindPthreadsCb, nullptr, TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
+                                            TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
+                       td_ta_delete(ta);
+               }
+
+               if (err == TD_NOLIBTHREAD) {
+                       logger.log_info("target does not appear to be multi-threaded");
+               } else if (err != TD_OK) {
+                       logger.log_info("WARNING: libthread_db not found, using fallback");
+                       // TODO: fallback
+               }
+       }
+
+       bool SymAddress(const char *sym_name, unsigned long *addr) {
+               for (const auto &sd : m_symdata) {
+                       for (int i = 0; i < sd->count; i++) {
+                               GElf_Sym sym;
+                               GElf_Sym *s;
+
+                               s = gelf_getsym(sd->data, i, &sym);
+                               if (!s)
+                                       continue;
+
+                               const char *st = elf_strptr(sd->elf, sd->shdr.sh_link, s->st_name);
+
+                               if (strcmp(st, sym_name) != 0)
+                                       continue;
+
+                               *addr = sd->start + s->st_value;
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       void SaveAUXVData(const std::string &exe_path, int mem_fd, std::ofstream &core_file) {
+               unsigned long debug_ptr = 0;
+               NoteCoreAUXV *auxv_note = nullptr;
+
+               for (auto &note : m_notes) {
+                       if (note->type == PT_PHDR) {
+                               auxv_note = static_cast<NoteCoreAUXV*>(note.get());
+                               break;
+                       }
+               }
+               if (!auxv_note)
+                       return;
+
+               auto *auxv_data = reinterpret_cast<const typename T::auxv_t*>(auxv_note->auxv().data());
+
+               auto phnum = AUXVval(auxv_data, AT_PHNUM);
+               auto phdr = AUXVval(auxv_data, AT_PHDR);
+
+               if (phdr == 0) {
+                       logger.log_info("PHDR not found for %s", exe_path);
+                       return;
+               }
+
+               typename T::Addr relocation = 0, dyn_addr = 0;
+
+               size_t i;
+
+               for (i = 0; i < phnum; i++) {
+                       auto addr = phdr + (sizeof(typename T::Phdr) * i) + offsetof(typename T::Phdr, p_type);
+                       uint32_t val;
+                       ReadFromFile(mem_fd, addr, &val, sizeof(val));
+
+                       if (val == PT_NULL) {
+                               break;
+                       } else if (val == PT_PHDR) {
+                               addr = phdr + (sizeof(typename T::Phdr) * i) + offsetof(typename T::Phdr, p_vaddr);
+                               ReadFromFile(mem_fd, addr, &relocation, sizeof(relocation));
+                               if (relocation > phdr) {
+                                       logger.log_error("relocation is greather than phdr");
+                                       return;
+                               }
+                               relocation = phdr - relocation;
+                       } else if (val == PT_DYNAMIC) {
+                               addr = phdr + (sizeof(typename T::Phdr) * i) + offsetof(typename T::Phdr, p_vaddr);
+                               ReadFromFile(mem_fd, addr, &dyn_addr, sizeof(dyn_addr));
+                       }
+               }
+
+               DumpData(mem_fd, core_file, phdr, sizeof(typename T::Phdr)*i, "phdr");
+
+               SaveSymData(exe_path, relocation);
+
+               dyn_addr += relocation;
+
+
+               for (i = 0; ; i++) {
+                       unsigned long addr = dyn_addr + (sizeof(typename T::Dyn)*i) + offsetof(typename T::Dyn, d_tag);
+                       uint32_t val;
+                       ReadFromFile(mem_fd, addr, &val, sizeof(val));
+                       if (val == DT_NULL)
+                               break;
+                       if (val == DT_DEBUG) {
+                               addr = dyn_addr + sizeof(typename T::Dyn)*i + offsetof(typename T::Dyn, d_un.d_ptr);
+                               ReadFromFile(mem_fd, addr, &debug_ptr, sizeof(debug_ptr));
+                       }
+               }
+               if (!debug_ptr) {
+                               logger.log_error("debug_ptr not found");
+                               return;
+               }
+               DumpData(mem_fd, core_file, dyn_addr, sizeof(typename T::Dyn)*i, "auxv dyns");
+               DumpData(mem_fd, core_file, debug_ptr, sizeof(struct r_debug), "auxv r_debug");
+
+               unsigned long ptr = debug_ptr;
+               ReadFromFile(mem_fd, ptr + offsetof(struct r_debug, r_map), &ptr, sizeof(ptr));
+
+               while (ptr) {
+                       unsigned long addr = 0;
+                       DumpData(mem_fd, core_file, ptr, sizeof(struct link_map), "auxv link_map");
+
+                       ReadFromFile(mem_fd, ptr + offsetof(struct link_map, l_name), &addr, sizeof(addr));
+
+                       char buff[PAGESIZE];
+                       ReadFromFile(mem_fd, addr, buff, sizeof(buff));
+
+                       if (buff[0] != 0) {
+                               DumpData(mem_fd, core_file, addr, strlen(buff) + 1, "l_name");
+                               ReadFromFile(mem_fd, ptr+offsetof(struct link_map, l_addr), &addr, sizeof(addr));
+                               SaveSymData(buff, addr);
+                       }
+
+                       ReadFromFile(mem_fd, ptr + offsetof(struct link_map, l_next), &ptr, sizeof(ptr));
+               }
+       }
+
+       unsigned long GetStackPointer(int task_nr, std::map<pid_t, user_regs_struct> &registers) {
+               unsigned long result;
+#if defined(__x86_64__)
+               result = registers[task_nr].rsp;
+#elif defined(__i386__)
+               result = registers[task_nr].esp;
+#elif defined(__arm__)
+               result = registers[task_nr].uregs[13];
+#elif defined(__aarch64__)
+               result = registers[task_nr].sp;
+#else
+#error Unsupported architecture
+#endif
+               return result;
+       }
+
+       void SaveStacks(int mem_fd, std::ofstream &core_file, std::vector<pid_t> tasks, std::map<pid_t, user_regs_struct> registers) {
+               for (auto task_nr : tasks) {
+                       unsigned long sp = GetStackPointer(task_nr, registers);
+                       auto *entry = FindRecordForMemAddress(sp);
+                       size_t len = entry->header.p_vaddr + entry->header.p_memsz - sp;
+                       auto out_addr = MemAddr2FileAddr(sp);
+                       DumpData(mem_fd, core_file, sp, out_addr, len, "stack nr " + std::to_string(task_nr));
+               }
+       }
+};
+#endif // CORE_HPP__
index 60dcb0b..135e56a 100644 (file)
@@ -61,12 +61,24 @@ struct ProgramTableHeader64 {
        uint64_t p_memsz;
        uint64_t p_align;
 };
+
+struct SymData {
+       unsigned long start;
+       Elf *elf;
+       Elf64_Shdr shdr;
+       Elf_Data *data;
+       int fd;
+       int count;
+       struct SymData *next;
+};
+
 #pragma pack(pop)
 
 struct Elf32 {
        typedef Elf32_Ehdr Ehdr;
        typedef Elf32_Phdr Phdr;
        typedef Elf32_Addr Addr;
+       typedef Elf32_Shdr Shdr;
        typedef Elf32_Off Off;
        typedef Elf32_Section Section;
        typedef Elf32_Versym Versym;
@@ -77,6 +89,8 @@ struct Elf32 {
        typedef Elf32_Xword Xword;
        typedef ProgramTableHeader32 ProgramTableHeader;
        typedef Notefile32 Notefile;
+       typedef Elf32_auxv_t auxv_t;
+       typedef Elf32_Dyn Dyn;
        typedef uint32_t uint;
        static const char ELFCLASS = ELFCLASS32;
 };
@@ -85,6 +99,7 @@ struct Elf64 {
        typedef Elf64_Ehdr Ehdr;
        typedef Elf64_Phdr Phdr;
        typedef Elf64_Addr Addr;
+       typedef Elf64_Shdr Shdr;
        typedef Elf64_Off Off;
        typedef Elf64_Section Section;
        typedef Elf64_Versym Versym;
@@ -95,6 +110,8 @@ struct Elf64 {
        typedef Elf64_Xword Xword;
        typedef ProgramTableHeader64 ProgramTableHeader;
        typedef Notefile64 Notefile;
+       typedef Elf64_auxv_t auxv_t;
+       typedef Elf64_Dyn Dyn;
        typedef uint64_t uint;
        static const char ELFCLASS = ELFCLASS64;
 };
index 5b97066..6e0869a 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "core.hpp"
 #include "helpers.hpp"
+#include "prochandle.hpp"
 #include "log.hpp"
 #include "maps.hpp"
 
 #include <stdexcept>
 #include <string>
 #include <vector>
+#include <map>
 
 template <typename T>
 class LiveDumper {
  private:
        pid_t m_pid;
        std::vector<pid_t> m_tpids;
+       std::map<pid_t,user_regs_struct> m_registers;
        Core<T> m_core;
        std::ofstream m_core_file;
        int prstatus_fd = -1;
@@ -162,12 +165,15 @@ class LiveDumper {
                if (prstatus_fd >= 0)
                        SaveRegsToPrStatusFd(registers);
 
+               m_registers[m_pid] = registers;
                m_core.AddPRSTATUSNote(registers, m_pid);
 
                for (const auto &pid : m_tpids) {
                        if (pid == m_pid)
                                continue;
                        GetRegs(&registers, pid);
+
+                       m_registers[pid] = registers;
                        m_core.AddPRSTATUSNote(registers, pid);
                }
 
@@ -176,7 +182,21 @@ class LiveDumper {
                m_core.AddAUXVNote(auxv);
        }
 
-       bool DumpCore(const std::string &path) {
+       void MarkImportantRegions(const std::vector<std::shared_ptr<MapRecord>> &records) {
+       }
+
+       std::string GetExePath(const pid_t pid) {
+               char BUFF[PATH_MAX];
+               std::string exe_path = std::string("/proc/" + std::to_string(pid) + "/exe");
+               ssize_t path_len;
+               if ((path_len = readlink(exe_path.c_str(), BUFF, sizeof(BUFF))) == -1) {
+                       std::cout << "GetExePath error from" << exe_path << std::endl;
+                       throw std::system_error(errno, std::system_category(), "GetExePath() for " + exe_path + " failed");
+               }
+               return std::string(BUFF, path_len);
+       }
+
+       bool DumpCore(const std::string &path, bool minicore) {
                bool result = true;
 
                try {
@@ -188,12 +208,20 @@ class LiveDumper {
                        const std::vector<std::shared_ptr<MapRecord>> records = ReadMaps();
 
                        AddNotes(records);
+                       MarkImportantRegions(records);
                        m_core.ImportMapRecords(records);
                        m_core.SaveELFHeader(m_core_file);
                        m_core.SaveProgramHeadersTable(m_core_file);
                        m_core.SaveNotes(m_core_file);
                        std::string mem_path = std::string("/proc/" + std::to_string(m_pid) + "/mem");
-                       m_core.SaveLoadable(mem_path, m_core_file);
+                       int mem_fd = open(mem_path.c_str(), O_RDONLY);
+                       m_core.SaveLoadable(mem_fd, m_core_file, minicore);
+                       if (minicore) {
+                               m_core.SaveAUXVData(GetExePath(m_pid), mem_fd, m_core_file);
+                               m_core.SavePthreadList(mem_fd, m_core_file, m_pid);
+                               m_core.SaveStacks(mem_fd, m_core_file, m_tpids, m_registers);
+                       }
+                       close(mem_fd);
                } catch (std::system_error &e) {
                        logger.log_error("DumpCore: %s", e.what());
                        result = false;
index f051dd1..311179d 100644 (file)
@@ -29,9 +29,9 @@ class Logger {
        void log(const LogMsgType type, const char *fmt...);
 };
 
-#define log_info(fmt, args...)    log(LogMsgType::INFO, fmt, args)
-#define log_warning(fmt, args...) log(LogMsgType::WARNING, fmt, args)
-#define log_error(fmt, args...)   log(LogMsgType::ERROR, fmt, args)
+#define log_info(fmt, args...)    log(LogMsgType::INFO, fmt, ##args)
+#define log_warning(fmt, args...) log(LogMsgType::WARNING, fmt, ##args)
+#define log_error(fmt, args...)   log(LogMsgType::ERROR, fmt, ##args)
 
 extern Logger logger;
 
index 3a4430c..f8d5a7e 100644 (file)
  */
 
 #include "livedumper.hpp"
+#include "log.hpp"
 
 #include <libelf.h>
 #include <unistd.h>
 
+#include <boost/exception/diagnostic_information.hpp>
+#include <boost/exception/info.hpp>
+#include <boost/exception_ptr.hpp>
+#include <exception>
+
 #if defined(__arm__) || defined(__i386__)
 #define ELF_TYPE Elf32
 #elif defined(__x86_64__) || defined(__aarch64__)
@@ -31,7 +37,8 @@ void help(const char *app_name) {
                  << "  " << app_name << " [-f file_name] [-P fd] <pid>" << std::endl
                  << std::endl
                  << "  -f <file_name>   output path" << std::endl
-                 << "  -P <fd>          descriptor nr" << std::endl;
+                 << "  -P <fd>          descriptor nr" << std::endl
+                 << "  -m               save minicore" << std::endl;
 }
 
 int main(int argc, char *argv[]) {
@@ -39,8 +46,9 @@ int main(int argc, char *argv[]) {
        int prstatus_fd = -1;
 
        std::string output_file;
+       bool minicore = false;
 
-       while ((opt = getopt(argc, argv, "hP:f:")) != -1) {
+       while ((opt = getopt(argc, argv, "hP:f:m")) != -1) {
                switch (opt) {
                case 'P':
                        prstatus_fd = atoi(optarg);
@@ -51,6 +59,9 @@ int main(int argc, char *argv[]) {
                case 'f':
                        output_file = optarg;
                        break;
+               case 'm':
+                       minicore = true;
+                       break;
                default:
                        help(argv[0]);
                        exit(EXIT_FAILURE);
@@ -72,5 +83,15 @@ int main(int argc, char *argv[]) {
        if (prstatus_fd > 0)
                dumper.setPrstatusFd(prstatus_fd);
 
-       return dumper.DumpCore(output_file) ? EXIT_SUCCESS : EXIT_FAILURE;
+       try {
+               return dumper.DumpCore(output_file, minicore) ? EXIT_SUCCESS : EXIT_FAILURE;
+       } catch (std::exception &e) {
+               logger.log_error("%s", e.what());
+               std::cout << e.what() << std::endl;
+               return EXIT_FAILURE;
+       } catch (...) {
+               logger.log_error("unspecified error");
+               std::cout << "unspecified error" << std::endl;
+               return EXIT_FAILURE;
+       }
 }
index 84a0555..ac90cb5 100644 (file)
@@ -49,6 +49,7 @@ struct MapRecord {
        uintptr_t offset;
        Permissions perms;
        std::string path;
+       bool important;
 
        bool IsLoadable() const {
                // we need only readable records
@@ -81,6 +82,13 @@ class Maps {
                return m_map_records;
        }
 
+       bool DoWeNeedThisRecord(const std::shared_ptr<MapRecord> record) {
+               return (record->path == "[vsyscall]" ||
+                       record->path == "[vdso]"     ||
+                       record->path == "[vectors]"  ||
+                       record->path == "[stack]");
+       }
+
        void Parse() {
                const std::string& maps_file_name = "/proc/" + std::to_string(m_pid) + "/maps";
 
@@ -92,7 +100,8 @@ class Maps {
                while (std::getline(maps_file, line)) {
                        std::shared_ptr<MapRecord> record = ParseLine(line);
 
-                       if (record->IsLoadable())
+                       record->important = DoWeNeedThisRecord(record);
+                       if ((record->perms & Permissions::Read) == Permissions::Read)
                                m_map_records.push_back(record);
                }
        }
index 6977c08..9cc8f92 100644 (file)
@@ -175,5 +175,9 @@ class NoteCoreAUXV : public Note {
        void SaveDataTo(std::ofstream &core_file) const {
                core_file.write(m_auxv.data(), m_auxv.size());
        }
+
+       const std::vector<char>& auxv() const {
+               return m_auxv;
+       }
 };
 #endif  // NOTE_HPP__
diff --git a/src/livedumper/prochandle.hpp b/src/livedumper/prochandle.hpp
new file mode 100644 (file)
index 0000000..01a0257
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef PROCHANDLE_HPP__
+#define PROCHANDLE_HPP__
+
+#include "helpers.hpp"
+#include "core.hpp"
+
+#include <iostream>
+
+typedef enum
+{
+       PS_OK,
+       PS_ERR,
+       PS_BADPID,
+       PS_BADLID,
+       PS_BADADDR,
+       PS_NOSYM,
+       PS_NOFREGS
+} ps_err_e;
+
+struct ps_prochandle {
+       void *core_obj;
+       bool bit32;
+       const int mem_fd;
+       std::ofstream &core_file;
+       const pid_t pid;
+
+       unsigned long int MemAddr2FileAddr(unsigned long int addr) {
+               if (bit32)
+                       return static_cast<Core<Elf32>*>(core_obj)->MemAddr2FileAddr(addr);
+               else
+                       return static_cast<Core<Elf64>*>(core_obj)->MemAddr2FileAddr(addr);
+       }
+
+       void DumpData(int fd, std::ofstream &output, unsigned long iaddress, unsigned long oaddress, size_t len, const std::string &desc) {
+               if (bit32)
+                       static_cast<Core<Elf32>*>(core_obj)->DumpData(fd, output, iaddress, oaddress, len, desc);
+               else
+                       static_cast<Core<Elf64>*>(core_obj)->DumpData(fd, output, iaddress, oaddress, len, desc);
+       }
+
+       bool SymAddress(const char *sym_name, unsigned long *addr) {
+               if (bit32)
+                       return static_cast<Core<Elf32>*>(core_obj)->SymAddress(sym_name, addr);
+               else
+                       return static_cast<Core<Elf64>*>(core_obj)->SymAddress(sym_name, addr);
+       }
+
+       void ReadFromFile(std::ifstream &input, unsigned long address, void *data, size_t len) {
+               if (bit32)
+                       static_cast<Core<Elf32>*>(core_obj)->ReadFromFile(input, address, data, len);
+               else
+                       static_cast<Core<Elf64>*>(core_obj)->ReadFromFile(input, address, data, len);
+       }
+
+       void ReadFromFile(const int fd, unsigned long address, void *data, size_t len) {
+               if (bit32)
+                       static_cast<Core<Elf32>*>(core_obj)->ReadFromFile(fd, address, data, len);
+               else
+                       static_cast<Core<Elf64>*>(core_obj)->ReadFromFile(fd, address, data, len);
+       }
+};
+
+extern "C" {
+       ps_err_e ps_pdread(struct ps_prochandle *ph, psaddr_t addr, void *buf, size_t size) {
+               ph->ReadFromFile(ph->mem_fd, reinterpret_cast<unsigned long>(addr), buf, size);
+
+               auto out_addr = ph->MemAddr2FileAddr(reinterpret_cast<unsigned long>(addr));
+               ph->DumpData(ph->mem_fd, ph->core_file, reinterpret_cast<unsigned long>(addr), out_addr, size, "pthread data");
+
+               return PS_OK;
+       }
+
+       ps_err_e ps_pdwrite(struct ps_prochandle *ph, psaddr_t addr, const void *buf, size_t size) {
+               return PS_OK;
+       }
+
+       ps_err_e ps_lgetregs(struct ps_prochandle *ph, lwpid_t lwpid, prgregset_t prgregset) {
+               return PS_OK;
+       }
+
+       ps_err_e ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lwpid, prfpregset_t *prfpregset) {
+               return PS_OK;
+       }
+
+       ps_err_e ps_lsetregs(struct ps_prochandle *ph, lwpid_t lwpid, const prgregset_t prgregset) {
+               return PS_OK;
+       }
+
+       ps_err_e ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lwpid, const prfpregset_t *prfpregset) {
+               return PS_OK;
+       }
+
+       pid_t ps_getpid(struct ps_prochandle *ph) {
+               return ph->pid;
+       }
+
+       ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name,
+                                                          const char *sym_name, psaddr_t *sym_addr) {
+               unsigned long addr;
+
+               if (!ph->SymAddress(sym_name, &addr))
+                       return PS_NOSYM;
+
+               *sym_addr = (psaddr_t)addr;
+               return PS_OK;
+       }
+}
+#endif // PROCHANDLE_HPP__
index 1c5b450..855e7e4 100644 (file)
@@ -45,7 +45,8 @@ class ProgramTableEntryNote : public ProgramTableEntryBase<T> {
 template <typename T>
 class ProgramTableEntryLoad : public ProgramTableEntryBase<T> {
  public:
-       ProgramTableEntryLoad() : ProgramTableEntryBase<T>(PT_LOAD) {
+       bool important;
+       ProgramTableEntryLoad() : ProgramTableEntryBase<T>(PT_LOAD), important(false) {
                this->header.p_flags = PF_R;
        }
 };