From 74955376082bbc7da31ad98b2c77e6953b27e37f Mon Sep 17 00:00:00 2001 From: Konstantin Baladurin Date: Mon, 17 Jul 2017 22:46:50 +0300 Subject: Make createdump build and work on ARM (#12798) --- src/CMakeLists.txt | 4 +- src/debug/createdump/crashinfo.cpp | 86 +++++++++++++++++++++++++---------- src/debug/createdump/crashinfo.h | 10 +++++ src/debug/createdump/createdump.h | 2 + src/debug/createdump/datatarget.cpp | 2 +- src/debug/createdump/dumpwriter.cpp | 40 +++++++++++------ src/debug/createdump/dumpwriter.h | 5 ++- src/debug/createdump/memoryregion.h | 15 ++++++- src/debug/createdump/threadinfo.cpp | 90 ++++++++++++++++++++++++++++++++++++- src/debug/createdump/threadinfo.h | 19 +++++++- 10 files changed, 226 insertions(+), 47 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 18ddf99314..ba17dc05ce 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -103,9 +103,9 @@ endfunction() if(CLR_CMAKE_PLATFORM_UNIX) if(CLR_CMAKE_PLATFORM_LINUX) - if(CLR_CMAKE_PLATFORM_UNIX_AMD64) + if(CLR_CMAKE_PLATFORM_UNIX_AMD64 OR CLR_CMAKE_PLATFORM_UNIX_ARM) add_subdirectory(debug/createdump) - endif(CLR_CMAKE_PLATFORM_UNIX_AMD64) + endif() endif(CLR_CMAKE_PLATFORM_LINUX) add_subdirectory(ToolBox/SOS/Strike) diff --git a/src/debug/createdump/crashinfo.cpp b/src/debug/createdump/crashinfo.cpp index edc31616de..d9642b309a 100644 --- a/src/debug/createdump/crashinfo.cpp +++ b/src/debug/createdump/crashinfo.cpp @@ -85,7 +85,7 @@ CrashInfo::EnumMemoryRegion( /* [in] */ CLRDATA_ADDRESS address, /* [in] */ ULONG32 size) { - InsertMemoryRegion(address, size); + InsertMemoryRegion((ULONG_PTR)address, size); return S_OK; } @@ -274,7 +274,7 @@ CrashInfo::GetAuxvEntries() if (auxvEntry.a_type < AT_MAX) { m_auxvValues[auxvEntry.a_type] = auxvEntry.a_un.a_val; - TRACE("AUXV: %lu = %016lx\n", auxvEntry.a_type, auxvEntry.a_un.a_val); + TRACE("AUXV: %" PRIu " = %" PRIxA "\n", auxvEntry.a_type, auxvEntry.a_un.a_val); result = true; } } @@ -334,7 +334,7 @@ CrashInfo::EnumerateModuleMappings() char* permissions = nullptr; char* moduleName = nullptr; - int c = sscanf(line, "%lx-%lx %m[-rwxsp] %lx %*[:0-9a-f] %*d %ms\n", &start, &end, &permissions, &offset, &moduleName); + int c = sscanf(line, "%" PRIx64 "-%" PRIx64 " %m[-rwxsp] %" PRIx64 " %*[:0-9a-f] %*d %ms\n", &start, &end, &permissions, &offset, &moduleName); if (c == 4 || c == 5) { // r = read @@ -416,10 +416,10 @@ CrashInfo::GetDSOInfo() { Phdr ph; if (!ReadMemory(phdrAddr, &ph, sizeof(ph))) { - fprintf(stderr, "ReadMemory(%p, %lx) phdr FAILED\n", phdrAddr, sizeof(ph)); + fprintf(stderr, "ReadMemory(%p, %" PRIx ") phdr FAILED\n", phdrAddr, sizeof(ph)); return false; } - TRACE("DSO: phdr %p type %d (%x) vaddr %016lx memsz %016lx offset %016lx\n", + TRACE("DSO: phdr %p type %d (%x) vaddr %" PRIxA " memsz %" PRIxA " offset %" PRIxA "\n", phdrAddr, ph.p_type, ph.p_type, ph.p_vaddr, ph.p_memsz, ph.p_offset); if (ph.p_type == PT_DYNAMIC) @@ -444,10 +444,10 @@ CrashInfo::GetDSOInfo() for (;;) { ElfW(Dyn) dyn; if (!ReadMemory(dynamicAddr, &dyn, sizeof(dyn))) { - fprintf(stderr, "ReadMemory(%p, %lx) dyn FAILED\n", dynamicAddr, sizeof(dyn)); + fprintf(stderr, "ReadMemory(%p, %" PRIx ") dyn FAILED\n", dynamicAddr, sizeof(dyn)); return false; } - TRACE("DSO: dyn %p tag %ld (%lx) d_ptr %016lx\n", dynamicAddr, dyn.d_tag, dyn.d_tag, dyn.d_un.d_ptr); + TRACE("DSO: dyn %p tag %" PRId " (%" PRIx ") d_ptr %" PRIxA "\n", dynamicAddr, dyn.d_tag, dyn.d_tag, dyn.d_un.d_ptr); if (dyn.d_tag == DT_DEBUG) { rdebugAddr = reinterpret_cast(dyn.d_un.d_ptr); } @@ -461,7 +461,7 @@ CrashInfo::GetDSOInfo() TRACE("DSO: rdebugAddr %p\n", rdebugAddr); struct r_debug debugEntry; if (!ReadMemory(rdebugAddr, &debugEntry, sizeof(debugEntry))) { - fprintf(stderr, "ReadMemory(%p, %lx) r_debug FAILED\n", rdebugAddr, sizeof(debugEntry)); + fprintf(stderr, "ReadMemory(%p, %" PRIx ") r_debug FAILED\n", rdebugAddr, sizeof(debugEntry)); return false; } @@ -470,7 +470,7 @@ CrashInfo::GetDSOInfo() for (struct link_map* linkMapAddr = debugEntry.r_map; linkMapAddr != nullptr;) { struct link_map map; if (!ReadMemory(linkMapAddr, &map, sizeof(map))) { - fprintf(stderr, "ReadMemory(%p, %lx) link_map FAILED\n", linkMapAddr, sizeof(map)); + fprintf(stderr, "ReadMemory(%p, %" PRIx ") link_map FAILED\n", linkMapAddr, sizeof(map)); return false; } // Read the module's name and make sure the memory is added to the core dump @@ -488,7 +488,7 @@ CrashInfo::GetDSOInfo() } } moduleName[i] = '\0'; - TRACE("\nDSO: link_map entry %p l_ld %p l_addr (Ehdr) %lx %s\n", linkMapAddr, map.l_ld, map.l_addr, (char*)moduleName); + TRACE("\nDSO: link_map entry %p l_ld %p l_addr (Ehdr) %" PRIx " %s\n", linkMapAddr, map.l_ld, map.l_addr, (char*)moduleName); // Read the ELF header and info adding it to the core dump if (!GetELFInfo(map.l_addr)) { @@ -506,6 +506,31 @@ NameCompare(const char* name, const char* sectionName) return strncmp(name, sectionName, strlen(sectionName) + 1) == 0; } +bool +ValidShdr(const std::set& mappings, uint64_t elfBaseAddr, Shdr *shdrAddr) +{ + bool isValid = false; + const char *moduleName = nullptr; + for (const MemoryRegion& region : mappings) + { + if (elfBaseAddr == region.StartAddress()) + moduleName = region.FileName(); + + if (!moduleName) + continue; + + if ((uint64_t)shdrAddr < region.StartAddress() || (uint64_t)shdrAddr >= region.EndAddress()) + continue; + + if (!strcmp(region.FileName(), moduleName)) { + isValid = true; + break; + } + } + + return isValid; +} + // // Add all the necessary ELF headers to the core dump // @@ -517,7 +542,7 @@ CrashInfo::GetELFInfo(uint64_t baseAddress) } Ehdr ehdr; if (!ReadMemory((void*)baseAddress, &ehdr, sizeof(ehdr))) { - fprintf(stderr, "ReadMemory(%p, %lx) ehdr FAILED\n", (void*)baseAddress, sizeof(ehdr)); + fprintf(stderr, "ReadMemory(%p, %" PRIx ") ehdr FAILED\n", (void*)baseAddress, sizeof(ehdr)); return false; } int phnum = ehdr.e_phnum; @@ -527,10 +552,14 @@ CrashInfo::GetELFInfo(uint64_t baseAddress) assert(ehdr.e_shstrndx != SHN_XINDEX); assert(ehdr.e_phentsize == sizeof(Phdr)); assert(ehdr.e_shentsize == sizeof(Shdr)); +#ifdef BIT64 assert(ehdr.e_ident[EI_CLASS] == ELFCLASS64); +#else + assert(ehdr.e_ident[EI_CLASS] == ELFCLASS32); +#endif assert(ehdr.e_ident[EI_DATA] == ELFDATA2LSB); - TRACE("ELF: type %d mach 0x%x ver %d flags 0x%x phnum %d phoff %016lx phentsize 0x%02x shnum %d shoff %016lx shentsize 0x%02x shstrndx %d\n", + TRACE("ELF: type %d mach 0x%x ver %d flags 0x%x phnum %d phoff %" PRIxA " phentsize 0x%02x shnum %d shoff %" PRIxA " shentsize 0x%02x shstrndx %d\n", ehdr.e_type, ehdr.e_machine, ehdr.e_version, ehdr.e_flags, phnum, ehdr.e_phoff, ehdr.e_phentsize, shnum, ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shstrndx); if (ehdr.e_phoff != 0 && phnum > 0) @@ -542,10 +571,10 @@ CrashInfo::GetELFInfo(uint64_t baseAddress) { Phdr ph; if (!ReadMemory(phdrAddr, &ph, sizeof(ph))) { - fprintf(stderr, "ReadMemory(%p, %lx) phdr FAILED\n", phdrAddr, sizeof(ph)); + fprintf(stderr, "ReadMemory(%p, %" PRIx ") phdr FAILED\n", phdrAddr, sizeof(ph)); return false; } - TRACE("ELF: phdr %p type %d (%x) vaddr %016lx memsz %016lx paddr %016lx filesz %016lx offset %016lx align %016lx\n", + TRACE("ELF: phdr %p type %d (%x) vaddr %" PRIxA " memsz %" PRIxA " paddr %" PRIxA " filesz %" PRIxA " offset %" PRIxA " align %" PRIxA "\n", phdrAddr, ph.p_type, ph.p_type, ph.p_vaddr, ph.p_memsz, ph.p_paddr, ph.p_filesz, ph.p_offset, ph.p_align); if (ph.p_type == PT_DYNAMIC || ph.p_type == PT_NOTE || ph.p_type == PT_GNU_EH_FRAME) @@ -563,13 +592,22 @@ CrashInfo::GetELFInfo(uint64_t baseAddress) if (baseAddress != m_auxvValues[AT_BASE] && ehdr.e_shoff != 0 && shnum > 0 && ehdr.e_shstrndx != SHN_UNDEF) { Shdr* shdrAddr = reinterpret_cast(baseAddress + ehdr.e_shoff); + Shdr* stringTableShdrAddr = shdrAddr + ehdr.e_shstrndx; + + // Check the section headers address. In some cases there isn't section header table in process memory. + if ((!ValidShdr(m_moduleMappings, baseAddress, shdrAddr) && !ValidShdr(m_otherMappings, baseAddress, shdrAddr)) || + (!ValidShdr(m_moduleMappings, baseAddress, stringTableShdrAddr) && !ValidShdr(m_otherMappings, baseAddress, stringTableShdrAddr))) { + TRACE("ELF: %2d shdr %p Invalid section headers table address\n", ehdr.e_shstrndx, shdrAddr); + return true; + } // Get the string table section header Shdr stringTableSectionHeader; - if (!ReadMemory(shdrAddr + ehdr.e_shstrndx, &stringTableSectionHeader, sizeof(stringTableSectionHeader))) { - TRACE("ELF: %2d shdr %p ReadMemory string table section header FAILED\n", ehdr.e_shstrndx, shdrAddr + ehdr.e_shstrndx); + if (!ReadMemory(stringTableShdrAddr, &stringTableSectionHeader, sizeof(stringTableSectionHeader))) { + TRACE("ELF: %2d shdr %p ReadMemory string table section header FAILED\n", ehdr.e_shstrndx, stringTableShdrAddr); return true; } + // Get the string table ArrayHolder stringTable = new char[stringTableSectionHeader.sh_size]; if (!ReadMemory((void*)(baseAddress + stringTableSectionHeader.sh_offset), stringTable.GetPtr(), stringTableSectionHeader.sh_size)) { @@ -584,7 +622,7 @@ CrashInfo::GetELFInfo(uint64_t baseAddress) TRACE("ELF: %2d shdr %p ReadMemory FAILED\n", sectionIndex, shdrAddr); return true; } - TRACE("ELF: %2d shdr %p type %2d (%x) addr %016lx offset %016lx size %016lx link %08x info %08x name %4d %s\n", + TRACE("ELF: %2d shdr %p type %2d (%x) addr %" PRIxA " offset %" PRIxA " size %" PRIxA " link %08x info %08x name %4d %s\n", sectionIndex, shdrAddr, sh.sh_type, sh.sh_type, sh.sh_addr, sh.sh_offset, sh.sh_size, sh.sh_link, sh.sh_info, sh.sh_name, &stringTable[sh.sh_name]); if (sh.sh_name != SHN_UNDEF && sh.sh_offset > 0 && sh.sh_size > 0) { @@ -597,7 +635,7 @@ CrashInfo::GetELFInfo(uint64_t baseAddress) NameCompare(name, ".note.gnu.ABI-tag") || NameCompare(name, ".gnu_debuglink")) { - TRACE("ELF: %s %p size %016lx\n", name, (void*)(baseAddress + sh.sh_offset), sh.sh_size); + TRACE("ELF: %s %p size %" PRIxA "\n", name, (void*)(baseAddress + sh.sh_offset), sh.sh_size); InsertMemoryRegion(baseAddress + sh.sh_offset, sh.sh_size); } } @@ -702,7 +740,7 @@ CrashInfo::EnumerateManagedModules(IXCLRDataProcess* clrDataProcess) DacpGetModuleData moduleData; if (SUCCEEDED(hr = moduleData.Request(clrDataModule))) { - TRACE("MODULE: %016lx dyn %d inmem %d file %d pe %016lx pdb %016lx", moduleData.LoadedPEAddress, moduleData.IsDynamic, + TRACE("MODULE: %" PRIA PRIx64 " dyn %d inmem %d file %d pe %" PRIA PRIx64 " pdb %" PRIA PRIx64, moduleData.LoadedPEAddress, moduleData.IsDynamic, moduleData.IsInMemory, moduleData.IsFileLayout, moduleData.PEFile, moduleData.InMemoryPdbAddress); if (!moduleData.IsDynamic && moduleData.LoadedPEAddress != 0) @@ -750,7 +788,7 @@ CrashInfo::ReplaceModuleMapping(CLRDATA_ADDRESS baseAddress, const char* pszName { // Add or change the module mapping for this PE image. The managed assembly images are // already in the module mappings list but in .NET 2.0 they have the name "/dev/zero". - MemoryRegion region(PF_R | PF_W | PF_X, baseAddress, baseAddress + PAGE_SIZE, 0, pszName); + MemoryRegion region(PF_R | PF_W | PF_X, (ULONG_PTR)baseAddress, (ULONG_PTR)(baseAddress + PAGE_SIZE), 0, pszName); const auto& found = m_moduleMappings.find(region); if (found == m_moduleMappings.end()) { @@ -854,7 +892,7 @@ CrashInfo::InsertMemoryRegion(const MemoryRegion& region) // The region overlaps/conflicts with one already in the set so add one page at a // time to avoid the overlapping pages. - uint64_t numberPages = region.Size() >> PAGE_SHIFT; + uint64_t numberPages = region.Size() / PAGE_SIZE; for (int p = 0; p < numberPages; p++, start += PAGE_SIZE) { @@ -901,8 +939,8 @@ CrashInfo::ValidRegion(const MemoryRegion& region) if (region.IsBackedByMemory()) { uint64_t start = region.StartAddress(); - uint64_t numberPages = region.Size() >> PAGE_SHIFT; + uint64_t numberPages = region.Size() / PAGE_SIZE; for (int p = 0; p < numberPages; p++, start += PAGE_SIZE) { BYTE buffer[1]; @@ -1012,11 +1050,11 @@ CrashInfo::GetStatus(pid_t pid, pid_t* ppid, pid_t* tgid, char** name) { if (strncmp("PPid:\t", line, 6) == 0) { - *ppid = _atoi64(line + 6); + *ppid = atoll(line + 6); } else if (strncmp("Tgid:\t", line, 6) == 0) { - *tgid = _atoi64(line + 6); + *tgid = atoll(line + 6); } else if (strncmp("Name:\t", line, 6) == 0) { diff --git a/src/debug/createdump/crashinfo.h b/src/debug/createdump/crashinfo.h index 43e82691aa..65f1d18730 100644 --- a/src/debug/createdump/crashinfo.h +++ b/src/debug/createdump/crashinfo.h @@ -5,8 +5,18 @@ // typedef for our parsing of the auxv variables in /proc/pid/auxv. #if defined(__i386) || defined(__ARM_EABI__) typedef Elf32_auxv_t elf_aux_entry; +#define PRIx PRIx32 +#define PRIu PRIu32 +#define PRId PRId32 +#define PRIA "08" +#define PRIxA PRIA PRIx #elif defined(__x86_64) || defined(__aarch64__) typedef Elf64_auxv_t elf_aux_entry; +#define PRIx PRIx64 +#define PRIu PRIu64 +#define PRId PRId64 +#define PRIA "016" +#define PRIxA PRIA PRIx #endif typedef __typeof__(((elf_aux_entry*) 0)->a_un.a_val) elf_aux_val_t; diff --git a/src/debug/createdump/createdump.h b/src/debug/createdump/createdump.h index 6f72f0e955..4892e5464b 100644 --- a/src/debug/createdump/createdump.h +++ b/src/debug/createdump/createdump.h @@ -49,6 +49,8 @@ typedef int T_CONTEXT; #include #include #include +#define __STDC_FORMAT_MACROS +#include #include #include #include diff --git a/src/debug/createdump/datatarget.cpp b/src/debug/createdump/datatarget.cpp index 9609fa30a7..dec52c707f 100644 --- a/src/debug/createdump/datatarget.cpp +++ b/src/debug/createdump/datatarget.cpp @@ -156,7 +156,7 @@ DumpDataTarget::ReadVirtual( /* [optional][out] */ ULONG32 *done) { assert(m_fd != -1); - size_t read = pread64(m_fd, buffer, size, (off64_t)address); + size_t read = pread64(m_fd, buffer, size, (off64_t)(ULONG_PTR)address); if (read == -1) { *done = 0; diff --git a/src/debug/createdump/dumpwriter.cpp b/src/debug/createdump/dumpwriter.cpp index 06c5b96d01..63c48cb2b3 100644 --- a/src/debug/createdump/dumpwriter.cpp +++ b/src/debug/createdump/dumpwriter.cpp @@ -207,7 +207,7 @@ DumpWriter::WriteDump() return false; } - TRACE("Writing %ld thread entries to core file\n", m_crashInfo.Threads().size()); + TRACE("Writing %zd thread entries to core file\n", m_crashInfo.Threads().size()); // Write all the thread's state and registers for (const ThreadInfo* thread : m_crashInfo.Threads()) @@ -227,7 +227,7 @@ DumpWriter::WriteDump() } } - TRACE("Writing %ld memory regions to core file\n", m_crashInfo.MemoryRegions().size()); + TRACE("Writing %zd memory regions to core file\n", m_crashInfo.MemoryRegions().size()); // Read from target process and write memory regions to core uint64_t total = 0; @@ -246,7 +246,7 @@ DumpWriter::WriteDump() uint32_t read = 0; if (FAILED(m_crashInfo.DataTarget()->ReadVirtual(address, m_tempBuffer, bytesToRead, &read))) { - fprintf(stderr, "ReadVirtual(%016lx, %08x) FAILED\n", address, bytesToRead); + fprintf(stderr, "ReadVirtual(%" PRIA PRIx64 ", %08x) FAILED\n", address, bytesToRead); return false; } @@ -260,7 +260,7 @@ DumpWriter::WriteDump() } } - printf("Written %ld bytes (%ld pages) to core file\n", total, total >> PAGE_SHIFT); + printf("Written %" PRId64 " bytes (%" PRId64 " pages) to core file\n", total, total / PAGE_SIZE); return true; } @@ -302,7 +302,7 @@ DumpWriter::WriteAuxv() nhdr.n_descsz = m_crashInfo.GetAuxvSize(); nhdr.n_type = NT_AUXV; - TRACE("Writing %ld auxv entries to core file\n", m_crashInfo.AuxvEntries().size()); + TRACE("Writing %zd auxv entries to core file\n", m_crashInfo.AuxvEntries().size()); if (!WriteData(&nhdr, sizeof(nhdr)) || !WriteData("CORE\0AUX", 8)) { @@ -319,9 +319,9 @@ DumpWriter::WriteAuxv() struct NTFileEntry { - uint64_t StartAddress; - uint64_t EndAddress; - uint64_t Offset; + unsigned long StartAddress; + unsigned long EndAddress; + unsigned long Offset; }; // Calculate the NT_FILE entries total size @@ -332,7 +332,7 @@ DumpWriter::GetNTFileInfoSize(size_t* alignmentBytes) size_t size = 0; // Header, CORE, entry count, page size - size = sizeof(Nhdr) + sizeof(NTFileEntry); + size = sizeof(Nhdr) + 8 + sizeof(count) + sizeof(size); // start_address, end_address, offset size += count * sizeof(NTFileEntry); @@ -380,12 +380,12 @@ DumpWriter::WriteNTFileInfo() size_t count = m_crashInfo.ModuleMappings().size(); size_t pageSize = PAGE_SIZE; - TRACE("Writing %ld NT_FILE entries to core file\n", m_crashInfo.ModuleMappings().size()); + TRACE("Writing %zd NT_FILE entries to core file\n", m_crashInfo.ModuleMappings().size()); if (!WriteData(&nhdr, sizeof(nhdr)) || !WriteData("CORE\0FIL", 8) || - !WriteData(&count, 8) || - !WriteData(&pageSize, 8)) { + !WriteData(&count, sizeof(count)) || + !WriteData(&pageSize, sizeof(pageSize))) { return false; } @@ -447,7 +447,7 @@ DumpWriter::WriteThread(const ThreadInfo& thread, int fatal_signal) return false; } -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) nhdr.n_descsz = sizeof(user_fpregs_struct); nhdr.n_type = NT_FPREGSET; if (!WriteData(&nhdr, sizeof(nhdr)) || @@ -457,12 +457,24 @@ DumpWriter::WriteThread(const ThreadInfo& thread, int fatal_signal) } #endif + nhdr.n_namesz = 6; + #if defined(__i386__) nhdr.n_descsz = sizeof(user_fpxregs_struct); nhdr.n_type = NT_PRXFPREG; if (!WriteData(&nhdr, sizeof(nhdr)) || !WriteData("LINUX\0\0\0", 8) || - !WriteData(&thread.FPXRegisters(), sizeof(user_fpxregs_struct))) { + !WriteData(thread.FPXRegisters(), sizeof(user_fpxregs_struct))) { + return false; + } +#endif + +#if defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__) + nhdr.n_descsz = sizeof(user_vfpregs_struct); + nhdr.n_type = NT_ARM_VFP; + if (!WriteData(&nhdr, sizeof(nhdr)) || + !WriteData("LINUX\0\0\0", 8) || + !WriteData(thread.VFPRegisters(), sizeof(user_vfpregs_struct))) { return false; } #endif diff --git a/src/debug/createdump/dumpwriter.h b/src/debug/createdump/dumpwriter.h index 7da0d63ccf..1d6b0f9d0e 100644 --- a/src/debug/createdump/dumpwriter.h +++ b/src/debug/createdump/dumpwriter.h @@ -60,11 +60,14 @@ private: const size_t GetThreadInfoSize() const { return m_crashInfo.Threads().size() * ((sizeof(Nhdr) + 8 + sizeof(prstatus_t)) -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) + sizeof(Nhdr) + 8 + sizeof(user_fpregs_struct) #endif #if defined(__i386__) + sizeof(Nhdr) + 8 + sizeof(user_fpxregs_struct) +#endif +#if defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__) + + sizeof(Nhdr) + 8 + sizeof(user_vfpregs_struct) #endif ); } diff --git a/src/debug/createdump/memoryregion.h b/src/debug/createdump/memoryregion.h index 1f6c5f53e6..e8e49aa149 100644 --- a/src/debug/createdump/memoryregion.h +++ b/src/debug/createdump/memoryregion.h @@ -2,6 +2,17 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if defined(__arm__) +#define PAGE_SIZE sysconf(_SC_PAGESIZE) +#define PAGE_MASK (~(PAGE_SIZE-1)) +#endif + +#ifdef BIT64 +#define PRIA "016" +#else +#define PRIA "08" +#endif + enum MEMORY_REGION_FLAGS : uint32_t { // PF_X = 0x01, // Execute @@ -109,7 +120,7 @@ public: void Trace() const { - TRACE("%s%016lx - %016lx (%06ld) %016lx %02x %s\n", IsBackedByMemory() ? "*" : " ", m_startAddress, m_endAddress, - (Size() >> PAGE_SHIFT), m_offset, m_flags, m_fileName != nullptr ? m_fileName : ""); + TRACE("%s%" PRIA PRIx64 " - %" PRIA PRIx64 " (%06" PRId64 ") %" PRIA PRIx64 " %02x %s\n", IsBackedByMemory() ? "*" : " ", m_startAddress, m_endAddress, + Size() / PAGE_SIZE, m_offset, m_flags, m_fileName != nullptr ? m_fileName : ""); } }; diff --git a/src/debug/createdump/threadinfo.cpp b/src/debug/createdump/threadinfo.cpp index 35a4f0d4cd..0bb439e50c 100644 --- a/src/debug/createdump/threadinfo.cpp +++ b/src/debug/createdump/threadinfo.cpp @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. #include "createdump.h" +#include #define FPREG_ErrorOffset(fpregs) *(DWORD*)&((fpregs).rip) #define FPREG_ErrorSelector(fpregs) *(((WORD*)&((fpregs).rip)) + 2) @@ -38,7 +39,12 @@ ThreadInfo::Initialize(ICLRDataTarget* dataTarget) return false; } } + +#if defined(__arm__) + TRACE("Thread %04x PC %08lx SP %08lx\n", m_tid, (unsigned long)m_gpRegisters.ARM_pc, (unsigned long)m_gpRegisters.ARM_sp); +#else TRACE("Thread %04x RIP %016llx RSP %016llx\n", m_tid, (unsigned long long)m_gpRegisters.rip, (unsigned long long)m_gpRegisters.rsp); +#endif return true; } @@ -71,6 +77,17 @@ ThreadInfo::GetRegistersWithPTrace() fprintf(stderr, "ptrace(GETFPXREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno)); return false; } +#elif defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__) + +#if defined(ARM_VFPREGS_SIZE) + assert(sizeof(m_vfpRegisters) == ARM_VFPREGS_SIZE); +#endif + + if (ptrace((__ptrace_request)PTRACE_GETVFPREGS, m_tid, nullptr, &m_vfpRegisters) == -1) + { + fprintf(stderr, "ptrace(PTRACE_GETVFPREGS, %d) FAILED %d (%s)\n", m_tid, errno, strerror(errno)); + return false; + } #endif return true; } @@ -133,6 +150,33 @@ ThreadInfo::GetRegistersWithDataTarget(ICLRDataTarget* dataTarget) assert(sizeof(context.FltSave.XmmRegisters) == sizeof(m_fpRegisters.xmm_space)); memcpy(m_fpRegisters.xmm_space, context.FltSave.XmmRegisters, sizeof(m_fpRegisters.xmm_space)); +#elif defined(__arm__) + m_gpRegisters.ARM_sp = context.Sp; + m_gpRegisters.ARM_lr = context.Lr; + m_gpRegisters.ARM_pc = context.Pc; + m_gpRegisters.ARM_cpsr = context.Cpsr; + + m_gpRegisters.ARM_r0 = context.R0; + m_gpRegisters.ARM_ORIG_r0 = context.R0; + m_gpRegisters.ARM_r1 = context.R1; + m_gpRegisters.ARM_r2 = context.R2; + m_gpRegisters.ARM_r3 = context.R3; + m_gpRegisters.ARM_r4 = context.R4; + m_gpRegisters.ARM_r5 = context.R5; + m_gpRegisters.ARM_r6 = context.R6; + m_gpRegisters.ARM_r7 = context.R7; + m_gpRegisters.ARM_r8 = context.R8; + m_gpRegisters.ARM_r9 = context.R9; + m_gpRegisters.ARM_r10 = context.R10; + m_gpRegisters.ARM_fp = context.R11; + m_gpRegisters.ARM_ip = context.R12; + +#if defined(__VFP_FP__) && !defined(__SOFTFP__) + m_vfpRegisters.fpscr = context.Fpscr; + + assert(sizeof(context.D) == sizeof(m_vfpRegisters.fpregs)); + memcpy(m_vfpRegisters.fpregs, context.D, sizeof(context.D)); +#endif #else #error Platform not supported #endif @@ -142,7 +186,11 @@ ThreadInfo::GetRegistersWithDataTarget(ICLRDataTarget* dataTarget) void ThreadInfo::GetThreadStack(const CrashInfo& crashInfo, uint64_t* startAddress, size_t* size) const { +#if defined(__arm__) + *startAddress = m_gpRegisters.ARM_sp & PAGE_MASK; +#else *startAddress = m_gpRegisters.rsp & PAGE_MASK; +#endif *size = 4 * PAGE_SIZE; const MemoryRegion* region = CrashInfo::SearchMemoryRegions(crashInfo.OtherMappings(), *startAddress); @@ -153,7 +201,7 @@ ThreadInfo::GetThreadStack(const CrashInfo& crashInfo, uint64_t* startAddress, s if (g_diagnostics) { - TRACE("Thread %04x stack found in other mapping (size %08lx): ", m_tid, *size); + TRACE("Thread %04x stack found in other mapping (size %08zx): ", m_tid, *size); region->Trace(); } } @@ -163,7 +211,11 @@ ThreadInfo::GetThreadStack(const CrashInfo& crashInfo, uint64_t* startAddress, s void ThreadInfo::GetThreadCode(uint64_t* startAddress, size_t* size) const { +#if defined(__arm__) + *startAddress = m_gpRegisters.ARM_pc & PAGE_MASK; +#elif defined(__x86_64__) *startAddress = m_gpRegisters.rip & PAGE_MASK; +#endif *size = PAGE_SIZE; } @@ -227,7 +279,41 @@ ThreadInfo::GetThreadContext(uint32_t flags, CONTEXT* context) const memcpy(context->FltSave.XmmRegisters, m_fpRegisters.xmm_space, sizeof(context->FltSave.XmmRegisters)); } // TODO: debug registers? -#else +#elif defined(__arm__) + if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL) + { + context->Sp = m_gpRegisters.ARM_sp; + context->Lr = m_gpRegisters.ARM_lr; + context->Pc = m_gpRegisters.ARM_pc; + context->Cpsr = m_gpRegisters.ARM_cpsr; + + } + if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER) + { + context->R0 = m_gpRegisters.ARM_r0; + context->R1 = m_gpRegisters.ARM_r1; + context->R2 = m_gpRegisters.ARM_r2; + context->R3 = m_gpRegisters.ARM_r3; + context->R4 = m_gpRegisters.ARM_r4; + context->R5 = m_gpRegisters.ARM_r5; + context->R6 = m_gpRegisters.ARM_r6; + context->R7 = m_gpRegisters.ARM_r7; + context->R8 = m_gpRegisters.ARM_r8; + context->R9 = m_gpRegisters.ARM_r9; + context->R10 = m_gpRegisters.ARM_r10; + context->R11 = m_gpRegisters.ARM_fp; + context->R12 = m_gpRegisters.ARM_ip; + } + if ((flags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) + { +#if defined(__VFP_FP__) && !defined(__SOFTFP__) + context->Fpscr = m_vfpRegisters.fpscr; + + assert(sizeof(context->D) == sizeof(m_vfpRegisters.fpregs)); + memcpy(context->D, m_vfpRegisters.fpregs, sizeof(context->D)); +#endif + } +#else #error Platform not supported #endif } diff --git a/src/debug/createdump/threadinfo.h b/src/debug/createdump/threadinfo.h index 8620219747..3756669ac3 100644 --- a/src/debug/createdump/threadinfo.h +++ b/src/debug/createdump/threadinfo.h @@ -4,6 +4,20 @@ class CrashInfo; +#if defined(__arm__) +#define user_regs_struct user_regs +#define user_fpregs_struct user_fpregs + +#if defined(__VFP_FP__) && !defined(__SOFTFP__) +struct user_vfpregs_struct +{ + unsigned long long fpregs[32]; + unsigned long fpscr; +} __attribute__((__packed__)); +#endif + +#endif + class ThreadInfo { private: @@ -14,6 +28,8 @@ private: struct user_fpregs_struct m_fpRegisters; // floating point registers #if defined(__i386__) struct user_fpxregs_struct m_fpxRegisters; // x86 floating point registers +#elif defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__) + struct user_vfpregs_struct m_vfpRegisters; // ARM VFP/NEON registers #endif public: @@ -33,10 +49,11 @@ public: const user_fpregs_struct* FPRegisters() const { return &m_fpRegisters; } #if defined(__i386__) const user_fpxregs_struct* FPXRegisters() const { return &m_fpxRegisters; } +#elif defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__) + const user_vfpregs_struct* VFPRegisters() const { return &m_vfpRegisters; } #endif private: bool GetRegistersWithPTrace(); bool GetRegistersWithDataTarget(ICLRDataTarget* dataTarget); }; - -- cgit v1.2.3