Make createdump build and work on ARM (dotnet/coreclr#12798)
authorKonstantin Baladurin <k.baladurin@partner.samsung.com>
Mon, 17 Jul 2017 19:46:50 +0000 (22:46 +0300)
committerMike McLaughlin <mikem@microsoft.com>
Mon, 17 Jul 2017 19:46:50 +0000 (12:46 -0700)
Commit migrated from https://github.com/dotnet/coreclr/commit/74955376082bbc7da31ad98b2c77e6953b27e37f

src/coreclr/src/CMakeLists.txt
src/coreclr/src/debug/createdump/crashinfo.cpp
src/coreclr/src/debug/createdump/crashinfo.h
src/coreclr/src/debug/createdump/createdump.h
src/coreclr/src/debug/createdump/datatarget.cpp
src/coreclr/src/debug/createdump/dumpwriter.cpp
src/coreclr/src/debug/createdump/dumpwriter.h
src/coreclr/src/debug/createdump/memoryregion.h
src/coreclr/src/debug/createdump/threadinfo.cpp
src/coreclr/src/debug/createdump/threadinfo.h

index 18ddf99..ba17dc0 100644 (file)
@@ -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)
index edc3161..d9642b3 100644 (file)
@@ -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<struct r_debug*>(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<MemoryRegion>& 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<Shdr*>(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<char> 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)
         {
index 43e8269..65f1d18 100644 (file)
@@ -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;
index 6f72f0e..4892e54 100644 (file)
@@ -49,6 +49,8 @@ typedef int T_CONTEXT;
 #include <fcntl.h>
 #include <elf.h>
 #include <link.h>
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
 #include <map>
 #include <set>
 #include <vector>
index 9609fa3..dec52c7 100644 (file)
@@ -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;
index 06c5b96..63c48cb 100644 (file)
@@ -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
index 7da0d63..1d6b0f9 100644 (file)
@@ -60,12 +60,15 @@ 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
         );
     }
 };
index 1f6c5f5..e8e49aa 100644 (file)
@@ -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 : "");
     }
 };
index 35a4f0d..0bb439e 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 #include "createdump.h"
+#include <asm/ptrace.h>
 
 #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
 }
index 8620219..3756669 100644 (file)
@@ -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);
 };
-