summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/debug/createdump/crashinfo.cpp86
-rw-r--r--src/debug/createdump/crashinfo.h10
-rw-r--r--src/debug/createdump/createdump.h2
-rw-r--r--src/debug/createdump/datatarget.cpp2
-rw-r--r--src/debug/createdump/dumpwriter.cpp40
-rw-r--r--src/debug/createdump/dumpwriter.h5
-rw-r--r--src/debug/createdump/memoryregion.h15
-rw-r--r--src/debug/createdump/threadinfo.cpp90
-rw-r--r--src/debug/createdump/threadinfo.h19
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<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)
{
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 <fcntl.h>
#include <elf.h>
#include <link.h>
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
#include <map>
#include <set>
#include <vector>
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,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
);
}
};
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 <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
}
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);
};
-