cp %{_reldir}/libmscordaccore.so %{buildroot}%{_datadir}/%{netcoreappdir}
cp %{_reldir}/libmscordbi.so %{buildroot}%{_datadir}/%{netcoreappdir}
cp %{_reldir}/libcoreclrtraceptprovider.so %{buildroot}%{_datadir}/%{netcoreappdir}
+cp %{_reldir}/libdnetmemoryenum.so %{buildroot}%{_datadir}/%{netcoreappdir}
cp %{_reldir}/System.Globalization.Native.so %{buildroot}%{_datadir}/%{netcoreappdir}
cp %{_reldir}/coreconsole %{buildroot}%{_datadir}/%{netcoreappdir}
cp %{_reldir}/crossgen %{buildroot}%{_datadir}/%{netcoreappdir}
if(CLR_CMAKE_PLATFORM_UNIX)
- if(CLR_CMAKE_PLATFORM_LINUX AND NOT CLR_CMAKE_PLATFORM_UNIX_X86)
+ if(CLR_CMAKE_PLATFORM_LINUX)
add_subdirectory(debug/createdump)
- endif(CLR_CMAKE_PLATFORM_LINUX AND NOT CLR_CMAKE_PLATFORM_UNIX_X86)
+ endif(CLR_CMAKE_PLATFORM_LINUX)
# Include the dummy c++ include files
include_directories("pal/inc/rt/cpp")
dumpwriter.cpp
)
+set(DNETMEMORYENUM_SOURCES
+ dnetmemoryenumlib.cpp
+ crashinfo.cpp
+ threadinfo.cpp
+ datatarget.cpp
+)
+
_add_library(createdump_lib
${CREATEDUMP_SOURCES}
)
+_add_library(dnetmemoryenum SHARED
+ ${DNETMEMORYENUM_SOURCES}
+ ${PAL_REDEFINES_FILE}
+)
+
+set_property(TARGET dnetmemoryenum PROPERTY POSITION_INDEPENDENT_CODE ON)
+
_add_executable(createdump
main.cpp
${PAL_REDEFINES_FILE}
)
add_dependencies(createdump pal_redefines_file)
+add_dependencies(dnetmemoryenum pal_redefines_file)
target_link_libraries(createdump
createdump_lib
mscordaccore
)
+target_link_libraries(dnetmemoryenum
+ # share the PAL in the dac module
+ mscordaccore
+)
+
add_dependencies(createdump mscordaccore)
+add_dependencies(dnetmemoryenum mscordaccore)
install_clr(createdump)
+install_clr(dnetmemoryenum)
// Suspends all the threads and creating a list of them. Should be the first before
// gather any info about the process.
//
-bool
-CrashInfo::EnumerateAndSuspendThreads()
+bool
+CrashInfo::EnumerateAndSuspendThreads(bool suspend)
{
char taskPath[128];
snprintf(taskPath, sizeof(taskPath), "/proc/%d/task", m_pid);
if (tid != 0)
{
// Don't suspend the threads if running under sos
- if (!m_sos)
+ if (!m_sos && suspend)
{
// Reference: http://stackoverflow.com/questions/18577956/how-to-use-ptrace-to-get-a-consistent-view-of-multiple-threads
if (ptrace(PTRACE_ATTACH, tid, nullptr, nullptr) != -1)
}
//
+// Set registers for all threads
+//
+bool
+CrashInfo::SetThreadsRegisters(const std::vector<elf_prstatus*> &statuses)
+{
+ for (ThreadInfo* thread : m_threads) {
+ for (elf_prstatus* status : statuses) {
+ if (thread->Tid() == status->pr_pid) {
+ thread->SetRegisters(status);
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+//
// Gather all the necessary crash dump info.
//
bool
-CrashInfo::GatherCrashInfo(MINIDUMP_TYPE minidumpType)
+CrashInfo::GatherCrashInfo(MINIDUMP_TYPE minidumpType, bool initialize_threads)
{
// Get the process info
if (!GetStatus(m_pid, &m_ppid, &m_tgid, &m_name))
{
return false;
}
- // Get the info about the threads (registers, etc.)
- for (ThreadInfo* thread : m_threads)
- {
- if (!thread->Initialize(m_sos ? m_dataTarget : nullptr))
+ if (initialize_threads) {
+ // Get the info about the threads (registers, etc.)
+ for (ThreadInfo* thread : m_threads)
{
- return false;
+ if (!thread->Initialize(m_sos ? m_dataTarget : nullptr))
+ {
+ return false;
+ }
}
}
// Get the auxv data
public:
CrashInfo(pid_t pid, ICLRDataTarget* dataTarget, bool sos);
virtual ~CrashInfo();
- bool EnumerateAndSuspendThreads();
- bool GatherCrashInfo(MINIDUMP_TYPE minidumpType);
+ bool EnumerateAndSuspendThreads(bool suspend = true);
+ bool SetThreadsRegisters(const std::vector<elf_prstatus*> &statuses);
+ bool GatherCrashInfo(MINIDUMP_TYPE minidumpType, bool initialize_threads = true);
void ResumeThreads();
bool ReadMemory(void* address, void* buffer, size_t size);
uint64_t GetBaseAddress(uint64_t ip);
--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdarg.h>
+#include <iostream>
+#include <vector>
+#include "createdump.h"
+#include "dnetmemoryenumlib.h"
+
+bool g_diagnostics = false;
+
+std::vector<SimpleMemoryRegion> sm_regions;
+
+static std::vector<SimpleMemoryRegion>
+get_regions(CrashInfo *crashInfo)
+{
+ std::vector<SimpleMemoryRegion> reg_vec;
+ for (const MemoryRegion& memoryRegion : crashInfo->MemoryRegions()) {
+ if (memoryRegion.IsBackedByMemory()) {
+ reg_vec.push_back({memoryRegion.StartAddress(), memoryRegion.Size()});
+ }
+ }
+ return reg_vec;
+}
+
+
+extern "C" int
+DotNetMemoryEnumInit()
+{
+ int exitCode = PAL_InitializeDLL();
+ return exitCode;
+}
+
+extern "C" void
+DotNetMemoryEnumFinish()
+{
+ PAL_TerminateEx(0);
+}
+
+extern "C" int
+DotNetMemoryEnumRegions(pid_t pid, elf_prstatus **statuses, int statuses_count,
+ DUMP_TYPE minidump_type, SimpleMemoryRegion **regions)
+{
+ g_diagnostics = true;
+
+ std::vector<elf_prstatus*> stats;
+ for (int i = 0; i < statuses_count; i++) {
+ stats.push_back(statuses[i]);
+ }
+
+ MINIDUMP_TYPE minidumpType;
+
+ switch (minidump_type) {
+ case DT_NORMAL:
+ default:
+ minidumpType = MiniDumpNormal;
+ break;
+ case DT_WITH_PRIV_AND_SHARED_MEM:
+ minidumpType = MiniDumpWithPrivateReadWriteMemory;
+ break;
+ case DT_FULL:
+ minidumpType = MiniDumpWithFullMemory;
+ break;
+ }
+
+ int exitCode = REGERR_OK;
+
+ if (pid != 0)
+ {
+ ReleaseHolder<DumpDataTarget> dataTarget = new DumpDataTarget(pid);
+ ReleaseHolder<CrashInfo> crashInfo = new CrashInfo(pid, dataTarget, true);
+
+ if (dataTarget->Initialize(crashInfo))
+ {
+ if (!crashInfo->EnumerateAndSuspendThreads(false))
+ {
+ return REGERR_ENUMERATION_ERROR;
+ }
+ crashInfo->SetThreadsRegisters(stats);
+ crashInfo->GatherCrashInfo(minidumpType, false);
+ sm_regions = get_regions(crashInfo);
+ *regions = sm_regions.data();
+ exitCode = sm_regions.size();
+ }
+ else
+ {
+ exitCode = REGERR_INITIALIZATION_ERROR;
+ }
+ }
+ else
+ {
+ exitCode = REGERR_WRONG_PID;
+ }
+ return exitCode;
+}
--- /dev/null
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DNETMEMORYENUMLIB_H__
+#define __DNETMEMORYENUMLIB_H__
+
+#include <stdint.h>
+#include <stdlib.h>
+
+struct SimpleMemoryRegion {
+ uintptr_t m_startAddress;
+ size_t m_size;
+};
+
+enum DUMP_TYPE {
+ DT_NORMAL = 0,
+ DT_WITH_PRIV_AND_SHARED_MEM,
+ DT_FULL
+};
+
+enum REG_ERR {
+ REGERR_OK = 0,
+ REGERR_WRONG_PID = -1,
+ REGERR_INITIALIZATION_ERROR = -2,
+ REGERR_ENUMERATION_ERROR = -3
+};
+
+extern "C" int DotNetMemoryEnumRegions(pid_t pid, elf_prstatus **statuses, int statuses_count,
+ DUMP_TYPE minidump_type, SimpleMemoryRegion **regions);
+extern "C" int DotNetMemoryEnumInit();
+extern "C" void DotNetMemoryEnumFinish();
+
+#endif
TRACE("Thread %04x PC %08lx SP %08lx\n", m_tid, (unsigned long)m_gpRegisters.ARM_pc, (unsigned long)m_gpRegisters.ARM_sp);
#elif defined(__x86_64__)
TRACE("Thread %04x RIP %016llx RSP %016llx\n", m_tid, (unsigned long long)m_gpRegisters.rip, (unsigned long long)m_gpRegisters.rsp);
+#elif defined(__i386__)
+ TRACE("Thread %04x EIP %016lx ESP %016lx\n", m_tid, (unsigned long)m_gpRegisters.eip, (unsigned long)m_gpRegisters.esp);
#else
#error "Unsupported architecture"
#endif
#endif
return true;
}
+void ThreadInfo::SetRegisters(elf_prstatus *prstatus)
+{
+#if defined(__x86_64__)
+ struct user_regs_struct *u_reg = (struct user_regs_struct *)&prstatus->pr_reg;
+ m_gpRegisters.rip = u_reg->rip;
+ m_gpRegisters.rbp = u_reg->rbp;
+ m_gpRegisters.rsp = u_reg->rsp;
+
+ m_gpRegisters.rax = u_reg->rax;
+ m_gpRegisters.rbx = u_reg->rbx;
+ m_gpRegisters.rcx = u_reg->rcx;
+ m_gpRegisters.rdx = u_reg->rdx;
+ m_gpRegisters.rsi = u_reg->rsi;
+ m_gpRegisters.rdi = u_reg->rdi;
+
+ m_gpRegisters.cs = u_reg->cs;
+ m_gpRegisters.gs = u_reg->gs;
+ m_gpRegisters.es = u_reg->es;
+ m_gpRegisters.fs = u_reg->fs;
+ m_gpRegisters.ds = u_reg->ds;
+ m_gpRegisters.ss = u_reg->ss;
+ m_gpRegisters.fs_base = u_reg->fs_base;
+ m_gpRegisters.gs_base = u_reg->gs_base;
+
+ m_gpRegisters.orig_rax = u_reg->orig_rax;
+
+ m_gpRegisters.r8 = u_reg->r8;
+ m_gpRegisters.r9 = u_reg->r9;
+ m_gpRegisters.r10 = u_reg->r10;
+ m_gpRegisters.r11 = u_reg->r11;
+ m_gpRegisters.r12 = u_reg->r12;
+ m_gpRegisters.r13 = u_reg->r13;
+ m_gpRegisters.r14 = u_reg->r14;
+ m_gpRegisters.r15 = u_reg->r15;
+
+ m_gpRegisters.eflags = u_reg->eflags;
+#elif defined(__i386__)
+ struct user_regs_struct *u_reg = (struct user_regs_struct *)&prstatus->pr_reg;
+ m_gpRegisters.ebx = u_reg->ebx;
+ m_gpRegisters.ecx = u_reg->ecx;
+ m_gpRegisters.edx = u_reg->edx;
+ m_gpRegisters.esi = u_reg->esi;
+ m_gpRegisters.edi = u_reg->edi;
+ m_gpRegisters.ebp = u_reg->ebp;
+ m_gpRegisters.eax = u_reg->eax;
+ m_gpRegisters.xds = u_reg->xds;
+ m_gpRegisters.xes = u_reg->xes;
+ m_gpRegisters.xfs = u_reg->xfs;
+ m_gpRegisters.xgs = u_reg->xgs;
+ m_gpRegisters.orig_eax = u_reg->orig_eax;
+ m_gpRegisters.eip = u_reg->eip;
+ m_gpRegisters.xcs = u_reg->xcs;
+ m_gpRegisters.eflags = u_reg->eflags;
+ m_gpRegisters.esp = u_reg->esp;
+ m_gpRegisters.xss = u_reg->xss;
+#elif defined(__arm__)
+
+#define REGS_REGULAR_NUM 13
+#define REG_FP 11
+#define REG_IP 12
+#define REG_SP 13
+#define REG_LR 14
+#define REG_PC 15
+#define REG_SPSR 16
+ struct user_regs *u_reg = (struct user_regs *)&prstatus->pr_reg;
+ m_gpRegisters.ARM_sp = u_reg->uregs[REG_SP];
+ m_gpRegisters.ARM_lr = u_reg->uregs[REG_LR];
+ m_gpRegisters.ARM_pc = u_reg->uregs[REG_PC];
+ m_gpRegisters.ARM_cpsr = u_reg->uregs[REG_SPSR];
+
+ m_gpRegisters.ARM_r0 = u_reg->uregs[0];
+ m_gpRegisters.ARM_ORIG_r0 = u_reg->uregs[0];
+ m_gpRegisters.ARM_r1 = u_reg->uregs[1];
+ m_gpRegisters.ARM_r2 = u_reg->uregs[2];
+ m_gpRegisters.ARM_r3 = u_reg->uregs[3];
+ m_gpRegisters.ARM_r4 = u_reg->uregs[4];
+ m_gpRegisters.ARM_r5 = u_reg->uregs[5];
+ m_gpRegisters.ARM_r6 = u_reg->uregs[6];
+ m_gpRegisters.ARM_r7 = u_reg->uregs[7];
+ m_gpRegisters.ARM_r8 = u_reg->uregs[8];
+ m_gpRegisters.ARM_r9 = u_reg->uregs[9];
+ m_gpRegisters.ARM_r10 = u_reg->uregs[10];
+ m_gpRegisters.ARM_fp = u_reg->uregs[REG_FP];
+ m_gpRegisters.ARM_ip = u_reg->uregs[REG_IP];
+#endif
+}
bool
ThreadInfo::GetRegistersWithDataTarget(ICLRDataTarget* pDataTarget)
assert(sizeof(context.D) == sizeof(m_vfpRegisters.fpregs));
memcpy(m_vfpRegisters.fpregs, context.D, sizeof(context.D));
#endif
-#else
+#elif defined(__i386__)
+ m_gpRegisters.ebp = context.Ebp;
+ m_gpRegisters.eip = context.Eip;
+ m_gpRegisters.eflags = context.EFlags;
+ m_gpRegisters.esp = context.Esp;
+ m_gpRegisters.edi = context.Edi;
+
+ m_gpRegisters.esi = context.Esi;
+ m_gpRegisters.ebx = context.Ebx;
+ m_gpRegisters.edx = context.Edx;
+ m_gpRegisters.ecx = context.Ecx;
+ m_gpRegisters.eax = context.Eax;
+ m_gpRegisters.orig_eax = context.Eax;
+#else
#error Platform not supported
#endif
return true;
startAddress = MCREG_Sp(m_gpRegisters) & PAGE_MASK;
#elif defined(__arm__)
startAddress = m_gpRegisters.ARM_sp & PAGE_MASK;
-#else
+#elif defined(__x86_64__)
startAddress = m_gpRegisters.rsp & PAGE_MASK;
+#elif defined(__i386__)
+ startAddress = m_gpRegisters.esp & PAGE_MASK;
#endif
size = 4 * PAGE_SIZE;
memcpy(context->D, m_vfpRegisters.fpregs, sizeof(context->D));
#endif
}
+#elif defined(__i386__)
+ if ((flags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
+ {
+ context->Ebp = m_gpRegisters.ebp;
+ context->Eip = m_gpRegisters.eip;
+ context->EFlags = m_gpRegisters.eflags;
+ context->Esp = m_gpRegisters.esp;
+ context->SegCs = m_gpRegisters.xcs;
+ context->SegSs = m_gpRegisters.xss;
+ context->SegGs_PAL_Undefined = m_gpRegisters.xgs;
+ context->SegFs_PAL_Undefined = m_gpRegisters.xfs;
+ context->SegEs_PAL_Undefined = m_gpRegisters.xes;
+ context->SegDs_PAL_Undefined = m_gpRegisters.xds;
+ }
+ if ((flags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
+ {
+ context->Edi = m_gpRegisters.edi;
+ context->Esi = m_gpRegisters.esi;
+ context->Ebx = m_gpRegisters.ebx;
+ context->Edx = m_gpRegisters.edx;
+ context->Ecx = m_gpRegisters.ecx;
+ context->Eax = m_gpRegisters.eax;
+ }
#else
#error Platform not supported
#endif
bool UnwindThread(CrashInfo& crashInfo, IXCLRDataProcess* pClrDataProcess);
void GetThreadStack(CrashInfo& crashInfo);
void GetThreadContext(uint32_t flags, CONTEXT* context) const;
+ void SetRegisters(elf_prstatus *prstatus);
inline pid_t Tid() const { return m_tid; }
inline pid_t Ppid() const { return m_ppid; }