Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike McLaughlin <mikem@microsoft.com>2021-07-12 18:55:14 +0300
committerGitHub <noreply@github.com>2021-07-12 18:55:14 +0300
commitf57b6e7308e9db32e63488aa5e8f938934f54cf0 (patch)
tree48ada362c45a760748668be25605a4398f602f44 /src/coreclr
parentf28318bf770f49aeaf8b2b67b440250732b7fbf3 (diff)
Add crash report to createdump for Linux Watson (#55438)
Add crash report to createdump for Linux Watson For Linux Watson the crash report will contains the .NET Core version, the faulting process name (the module/assembly containing Main) and the managed exception info (including the exception HRESULT) and thread stack trace of the thread the caused the crash. Add the CLRDATA_MODULE_IS_MAIN_MODULE flag to the DAC's IXCLRDataModule::GetFlags API. Add code to get the managed method name and write it out as "method_name" (even on MacOS). Add native frame symbolization (unmanaged_name) using dladdr. Only get the image info once and save in a global Demangle the stack frame symbols Only write PH_HDR_CANARY section if neccessary
Diffstat (limited to 'src/coreclr')
-rw-r--r--src/coreclr/debug/createdump/CMakeLists.txt1
-rw-r--r--src/coreclr/debug/createdump/crashinfo.cpp87
-rw-r--r--src/coreclr/debug/createdump/crashinfo.h11
-rw-r--r--src/coreclr/debug/createdump/crashinfomac.cpp36
-rw-r--r--src/coreclr/debug/createdump/crashinfounix.cpp10
-rw-r--r--src/coreclr/debug/createdump/crashreportwriter.cpp146
-rw-r--r--src/coreclr/debug/createdump/crashreportwriter.h6
-rw-r--r--src/coreclr/debug/createdump/createdump.h2
-rw-r--r--src/coreclr/debug/createdump/datatarget.h4
-rw-r--r--src/coreclr/debug/createdump/dumpwriterelf.cpp35
-rw-r--r--src/coreclr/debug/createdump/dumpwriterelf.h4
-rw-r--r--src/coreclr/debug/createdump/dumpwritermacho.h4
-rw-r--r--src/coreclr/debug/createdump/moduleinfo.h49
-rw-r--r--src/coreclr/debug/createdump/stackframe.h42
-rw-r--r--src/coreclr/debug/createdump/threadinfo.cpp18
-rw-r--r--src/coreclr/debug/createdump/threadinfo.h25
-rw-r--r--src/coreclr/debug/createdump/threadinfomac.cpp1
-rw-r--r--src/coreclr/debug/createdump/threadinfounix.cpp3
-rw-r--r--src/coreclr/debug/daccess/task.cpp11
-rw-r--r--src/coreclr/inc/xclrdata.idl1
-rw-r--r--src/coreclr/pal/prebuilt/inc/xclrdata.h3
21 files changed, 364 insertions, 135 deletions
diff --git a/src/coreclr/debug/createdump/CMakeLists.txt b/src/coreclr/debug/createdump/CMakeLists.txt
index 5d766d53da1..f0093b7cb66 100644
--- a/src/coreclr/debug/createdump/CMakeLists.txt
+++ b/src/coreclr/debug/createdump/CMakeLists.txt
@@ -86,6 +86,7 @@ endif(CLR_CMAKE_HOST_OSX)
dbgutil
# share the PAL in the dac module
mscordaccore
+ dl
)
add_dependencies(createdump mscordaccore)
diff --git a/src/coreclr/debug/createdump/crashinfo.cpp b/src/coreclr/debug/createdump/crashinfo.cpp
index bc444815415..807036fd200 100644
--- a/src/coreclr/debug/createdump/crashinfo.cpp
+++ b/src/coreclr/debug/createdump/crashinfo.cpp
@@ -6,13 +6,17 @@
// This is for the PAL_VirtualUnwindOutOfProc read memory adapter.
CrashInfo* g_crashInfo;
+static bool ModuleInfoCompare(const ModuleInfo* lhs, const ModuleInfo* rhs) { return lhs->BaseAddress() < rhs->BaseAddress(); }
+
CrashInfo::CrashInfo(pid_t pid, bool gatherFrames, pid_t crashThread, uint32_t signal) :
m_ref(1),
m_pid(pid),
m_ppid(-1),
+ m_hdac(nullptr),
m_gatherFrames(gatherFrames),
m_crashThread(crashThread),
- m_signal(signal)
+ m_signal(signal),
+ m_moduleInfos(&ModuleInfoCompare)
{
g_crashInfo = this;
#ifdef __APPLE__
@@ -31,6 +35,20 @@ CrashInfo::~CrashInfo()
delete thread;
}
m_threads.clear();
+
+ // Clean up the modules
+ for (ModuleInfo* module : m_moduleInfos)
+ {
+ delete module;
+ }
+ m_moduleInfos.clear();
+
+ // Unload DAC module
+ if (m_hdac != nullptr)
+ {
+ FreeLibrary(m_hdac);
+ m_hdac = nullptr;
+ }
#ifdef __APPLE__
if (m_task != 0)
{
@@ -191,7 +209,6 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType)
PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = nullptr;
ICLRDataEnumMemoryRegions* pClrDataEnumRegions = nullptr;
IXCLRDataProcess* pClrDataProcess = nullptr;
- HMODULE hdac = nullptr;
HRESULT hr = S_OK;
bool result = false;
@@ -205,13 +222,13 @@ CrashInfo::EnumerateMemoryRegionsWithDAC(MINIDUMP_TYPE minidumpType)
dacPath.append(MAKEDLLNAME_A("mscordaccore"));
// Load and initialize the DAC
- hdac = LoadLibraryA(dacPath.c_str());
- if (hdac == nullptr)
+ m_hdac = LoadLibraryA(dacPath.c_str());
+ if (m_hdac == nullptr)
{
fprintf(stderr, "LoadLibraryA(%s) FAILED %d\n", dacPath.c_str(), GetLastError());
goto exit;
}
- pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(hdac, "CLRDataCreateInstance");
+ pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(m_hdac, "CLRDataCreateInstance");
if (pfnCLRDataCreateInstance == nullptr)
{
fprintf(stderr, "GetProcAddress(CLRDataCreateInstance) FAILED %d\n", GetLastError());
@@ -262,10 +279,6 @@ exit:
{
pClrDataProcess->Release();
}
- if (hdac != nullptr)
- {
- FreeLibrary(hdac);
- }
return result;
}
@@ -347,10 +360,13 @@ CrashInfo::EnumerateManagedModules(IXCLRDataProcess* pClrDataProcess)
bool
CrashInfo::UnwindAllThreads(IXCLRDataProcess* pClrDataProcess)
{
+ ReleaseHolder<ISOSDacInterface> pSos = nullptr;
+ pClrDataProcess->QueryInterface(__uuidof(ISOSDacInterface), (void**)&pSos);
+
// For each native and managed thread
for (ThreadInfo* thread : m_threads)
{
- if (!thread->UnwindThread(pClrDataProcess)) {
+ if (!thread->UnwindThread(pClrDataProcess, pSos)) {
return false;
}
}
@@ -426,9 +442,9 @@ CrashInfo::GetBaseAddressFromAddress(uint64_t address)
uint64_t
CrashInfo::GetBaseAddressFromName(const char* moduleName)
{
- for (const ModuleInfo& moduleInfo : m_moduleInfos)
+ for (const ModuleInfo* moduleInfo : m_moduleInfos)
{
- std::string name = GetFileName(moduleInfo.ModuleName());
+ std::string name = GetFileName(moduleInfo->ModuleName());
#ifdef __APPLE__
// Module names are case insenstive on MacOS
if (strcasecmp(name.c_str(), moduleName) == 0)
@@ -436,7 +452,7 @@ CrashInfo::GetBaseAddressFromName(const char* moduleName)
if (name.compare(moduleName) == 0)
#endif
{
- return moduleInfo.BaseAddress();
+ return moduleInfo->BaseAddress();
}
}
return 0;
@@ -445,14 +461,14 @@ CrashInfo::GetBaseAddressFromName(const char* moduleName)
//
// Return the module info for the base address
//
-const ModuleInfo*
+ModuleInfo*
CrashInfo::GetModuleInfoFromBaseAddress(uint64_t baseAddress)
{
ModuleInfo search(baseAddress);
- const auto& found = m_moduleInfos.find(search);
+ const auto& found = m_moduleInfos.find(&search);
if (found != m_moduleInfos.end())
{
- return &*found;
+ return *found;
}
return nullptr;
}
@@ -475,11 +491,12 @@ void
CrashInfo::AddModuleInfo(bool isManaged, uint64_t baseAddress, IXCLRDataModule* pClrDataModule, const std::string& moduleName)
{
ModuleInfo moduleInfo(baseAddress);
- const auto& found = m_moduleInfos.find(moduleInfo);
+ const auto& found = m_moduleInfos.find(&moduleInfo);
if (found == m_moduleInfos.end())
{
uint32_t timeStamp = 0;
uint32_t imageSize = 0;
+ bool isMainModule = false;
GUID mvid;
if (isManaged)
{
@@ -511,11 +528,18 @@ CrashInfo::AddModuleInfo(bool isManaged, uint64_t baseAddress, IXCLRDataModule*
}
if (pClrDataModule != nullptr)
{
+ ULONG32 flags = 0;
+ pClrDataModule->GetFlags(&flags);
+ isMainModule = (flags & CLRDATA_MODULE_IS_MAIN_MODULE) != 0;
pClrDataModule->GetVersionId(&mvid);
}
- TRACE("MODULE: timestamp %08x size %08x %s %s\n", timeStamp, imageSize, FormatGuid(&mvid).c_str(), moduleName.c_str());
+ TRACE("MODULE: timestamp %08x size %08x %s %s%s\n", timeStamp, imageSize, FormatGuid(&mvid).c_str(), isMainModule ? "*" : "", moduleName.c_str());
+ }
+ ModuleInfo* moduleInfo = new ModuleInfo(isManaged, baseAddress, timeStamp, imageSize, &mvid, moduleName);
+ if (isMainModule) {
+ m_mainModule = moduleInfo;
}
- m_moduleInfos.insert(ModuleInfo(isManaged, baseAddress, timeStamp, imageSize, &mvid, moduleName));
+ m_moduleInfos.insert(moduleInfo);
}
}
@@ -738,6 +762,31 @@ CrashInfo::TraceVerbose(const char* format, ...)
}
//
+// Lookup a symbol in a module. The caller needs to call "free()" on symbol returned.
+//
+const char*
+ModuleInfo::GetSymbolName(uint64_t address)
+{
+ LoadModule();
+
+ if (m_localBaseAddress != 0)
+ {
+ uint64_t localAddress = m_localBaseAddress + (address - m_baseAddress);
+ Dl_info info;
+ if (dladdr((void*)localAddress, &info) != 0)
+ {
+ if (info.dli_sname != nullptr)
+ {
+ int status = -1;
+ char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status);
+ return status == 0 ? demangled : strdup(info.dli_sname);
+ }
+ }
+ }
+ return nullptr;
+}
+
+//
// Returns just the file name portion of a file path
//
const std::string
diff --git a/src/coreclr/debug/createdump/crashinfo.h b/src/coreclr/debug/createdump/crashinfo.h
index f315b98dd28..199144e1754 100644
--- a/src/coreclr/debug/createdump/crashinfo.h
+++ b/src/coreclr/debug/createdump/crashinfo.h
@@ -46,6 +46,7 @@ private:
pid_t m_pid; // pid
pid_t m_ppid; // parent pid
pid_t m_tgid; // process group
+ HMODULE m_hdac; // dac module handle when loaded
bool m_gatherFrames; // if true, add the native and managed stack frames to the thread info
pid_t m_crashThread; // crashing thread id or 0 if none
uint32_t m_signal; // crash signal code or 0 if none
@@ -68,7 +69,12 @@ private:
std::set<MemoryRegion> m_otherMappings; // other memory mappings
std::set<MemoryRegion> m_memoryRegions; // memory regions from DAC, etc.
std::set<MemoryRegion> m_moduleAddresses; // memory region to module base address
- std::set<ModuleInfo> m_moduleInfos; // module infos (base address and module name)
+ std::set<ModuleInfo*, bool (*)(const ModuleInfo* lhs, const ModuleInfo* rhs)> m_moduleInfos; // module infos (base address and module name)
+ ModuleInfo* m_mainModule; // the module containing "Main"
+
+ // no public copy constructor
+ CrashInfo(const CrashInfo&) = delete;
+ void operator=(const CrashInfo&) = delete;
public:
CrashInfo(pid_t pid, bool gatherFrames, pid_t crashThread, uint32_t signal);
@@ -82,7 +88,7 @@ public:
bool ReadProcessMemory(void* address, void* buffer, size_t size, size_t* read); // read raw memory
uint64_t GetBaseAddressFromAddress(uint64_t address);
uint64_t GetBaseAddressFromName(const char* moduleName);
- const ModuleInfo* GetModuleInfoFromBaseAddress(uint64_t baseAddress);
+ ModuleInfo* GetModuleInfoFromBaseAddress(uint64_t baseAddress);
void AddModuleAddressRange(uint64_t startAddress, uint64_t endAddress, uint64_t baseAddress);
void AddModuleInfo(bool isManaged, uint64_t baseAddress, IXCLRDataModule* pClrDataModule, const std::string& moduleName);
void InsertMemoryRegion(uint64_t address, size_t size);
@@ -98,6 +104,7 @@ public:
inline const pid_t CrashThread() const { return m_crashThread; }
inline const uint32_t Signal() const { return m_signal; }
inline const std::string& Name() const { return m_name; }
+ inline const ModuleInfo* MainModule() const { return m_mainModule; }
inline const std::vector<ThreadInfo*> Threads() const { return m_threads; }
inline const std::set<MemoryRegion> ModuleMappings() const { return m_moduleMappings; }
diff --git a/src/coreclr/debug/createdump/crashinfomac.cpp b/src/coreclr/debug/createdump/crashinfomac.cpp
index 4461d2a8c96..ad9c247e37d 100644
--- a/src/coreclr/debug/createdump/crashinfomac.cpp
+++ b/src/coreclr/debug/createdump/crashinfomac.cpp
@@ -380,3 +380,39 @@ CrashInfo::ReadProcessMemory(void* address, void* buffer, size_t size, size_t* r
*read = numberOfBytesRead;
return size == 0 || numberOfBytesRead > 0;
}
+
+const struct dyld_all_image_infos* g_image_infos = nullptr;
+
+void
+ModuleInfo::LoadModule()
+{
+ if (m_module == nullptr)
+ {
+ m_module = dlopen(m_moduleName.c_str(), RTLD_LAZY);
+ if (m_module != nullptr)
+ {
+ if (g_image_infos == nullptr)
+ {
+ struct task_dyld_info dyld_info;
+ mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+ kern_return_t result = task_info(mach_task_self_, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
+ if (result == KERN_SUCCESS)
+ {
+ g_image_infos = (const struct dyld_all_image_infos*)dyld_info.all_image_info_addr;
+ }
+ }
+ if (g_image_infos != nullptr)
+ {
+ for (int i = 0; i < g_image_infos->infoArrayCount; ++i)
+ {
+ const struct dyld_image_info* image = g_image_infos->infoArray + i;
+ if (strcasecmp(image->imageFilePath, m_moduleName.c_str()) == 0)
+ {
+ m_localBaseAddress = (uint64_t)image->imageLoadAddress;
+ break;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/coreclr/debug/createdump/crashinfounix.cpp b/src/coreclr/debug/createdump/crashinfounix.cpp
index 2cc1eb6c688..2f9605554ad 100644
--- a/src/coreclr/debug/createdump/crashinfounix.cpp
+++ b/src/coreclr/debug/createdump/crashinfounix.cpp
@@ -414,3 +414,13 @@ GetStatus(pid_t pid, pid_t* ppid, pid_t* tgid, std::string* name)
fclose(statusFile);
return true;
}
+
+void
+ModuleInfo::LoadModule()
+{
+ if (m_module == nullptr)
+ {
+ m_module = dlopen(m_moduleName.c_str(), RTLD_LAZY);
+ m_localBaseAddress = ((struct link_map*)m_module)->l_addr;
+ }
+}
diff --git a/src/coreclr/debug/createdump/crashreportwriter.cpp b/src/coreclr/debug/createdump/crashreportwriter.cpp
index 9cac899968f..40d8dbdba76 100644
--- a/src/coreclr/debug/createdump/crashreportwriter.cpp
+++ b/src/coreclr/debug/createdump/crashreportwriter.cpp
@@ -51,20 +51,19 @@ CrashReportWriter::WriteCrashReport(const std::string& dumpFileName)
}
}
-#ifdef __APPLE__
-
void
CrashReportWriter::WriteCrashReport()
{
- const char* exceptionType = nullptr;
OpenObject("payload");
- WriteValue("protocol_version", "0.0.7");
+ WriteValue("protocol_version", "1.0.0");
OpenObject("configuration");
#if defined(__x86_64__)
WriteValue("architecture", "amd64");
#elif defined(__aarch64__)
WriteValue("architecture", "arm64");
+#elif defined(__arm__)
+ WriteValue("architecture", "arm");
#endif
std::string version;
assert(strncmp(sccsid, "@(#)Version ", 12) == 0);
@@ -73,6 +72,13 @@ CrashReportWriter::WriteCrashReport()
WriteValue("version", version.c_str());
CloseObject(); // configuration
+ // The main module was saved away in the crash info
+ if (m_crashInfo.MainModule()->BaseAddress() != 0)
+ {
+ WriteValue("process_name", GetFileName(m_crashInfo.MainModule()->ModuleName()).c_str());
+ }
+
+ const char* exceptionType = nullptr;
OpenArray("threads");
for (const ThreadInfo* thread : m_crashInfo.Threads())
{
@@ -131,6 +137,10 @@ CrashReportWriter::WriteCrashReport()
{
WriteValue("managed_exception_type", thread->ManagedExceptionType().c_str());
}
+ if (thread->ManagedExceptionHResult() != 0)
+ {
+ WriteValue32("managed_exception_hresult", thread->ManagedExceptionHResult());
+ }
WriteValue64("native_thread_id", thread->Tid());
OpenObject("ctx");
WriteValue64("IP", thread->GetInstructionPointer());
@@ -148,7 +158,7 @@ CrashReportWriter::WriteCrashReport()
}
CloseArray(); // threads
CloseObject(); // payload
-
+#ifdef __APPLE__
OpenObject("parameters");
if (exceptionType != nullptr)
{
@@ -158,8 +168,35 @@ CrashReportWriter::WriteCrashReport()
WriteSysctl("hw.model", "SystemModel");
WriteValue("SystemManufacturer", "apple");
CloseObject(); // parameters
+#endif // __APPLE__
}
+#ifdef __APPLE__
+
+void
+CrashReportWriter::WriteSysctl(const char* sysctlname, const char* valueName)
+{
+ size_t size = 0;
+ if (sysctlbyname(sysctlname, nullptr, &size, NULL, 0) >= 0)
+ {
+ ArrayHolder<char> buffer = new char[size];
+ if (sysctlbyname(sysctlname, buffer, &size, NULL, 0) >= 0)
+ {
+ WriteValue(valueName, buffer);
+ }
+ else
+ {
+ TRACE("sysctlbyname(%s) 1 FAILED %s\n", sysctlname, strerror(errno));
+ }
+ }
+ else
+ {
+ TRACE("sysctlbyname(%s) 2 FAILED %s\n", sysctlname, strerror(errno));
+ }
+}
+
+#endif // __APPLE__
+
void
CrashReportWriter::WriteStackFrame(const StackFrame& frame)
{
@@ -167,16 +204,26 @@ CrashReportWriter::WriteStackFrame(const StackFrame& frame)
WriteValueBool("is_managed", frame.IsManaged());
WriteValue64("module_address", frame.ModuleAddress());
WriteValue64("stack_pointer", frame.StackPointer());
- WriteValue64("native_address", frame.ReturnAddress());
+ WriteValue64("native_address", frame.InstructionPointer());
WriteValue64("native_offset", frame.NativeOffset());
if (frame.IsManaged())
{
WriteValue32("token", frame.Token());
WriteValue32("il_offset", frame.ILOffset());
}
+ IXCLRDataMethodInstance* pMethod = frame.GetMethod();
+ if (pMethod != nullptr)
+ {
+ ArrayHolder<WCHAR> wszUnicodeName = new WCHAR[MAX_LONGPATH + 1];
+ if (SUCCEEDED(pMethod->GetName(0, MAX_LONGPATH, nullptr, wszUnicodeName)))
+ {
+ std::string methodName = FormatString("%S", wszUnicodeName.GetPtr());
+ WriteValue("method_name", methodName.c_str());
+ }
+ }
if (frame.ModuleAddress() != 0)
{
- const ModuleInfo* moduleInfo = m_crashInfo.GetModuleInfoFromBaseAddress(frame.ModuleAddress());
+ ModuleInfo* moduleInfo = m_crashInfo.GetModuleInfoFromBaseAddress(frame.ModuleAddress());
if (moduleInfo != nullptr)
{
std::string moduleName = GetFileName(moduleInfo->ModuleName());
@@ -189,6 +236,12 @@ CrashReportWriter::WriteStackFrame(const StackFrame& frame)
}
else
{
+ const char* symbol = moduleInfo->GetSymbolName(frame.InstructionPointer());
+ if (symbol != nullptr)
+ {
+ WriteValue("unmanaged_name", symbol);
+ free((void*)symbol);
+ }
WriteValue("native_module", moduleName.c_str());
}
}
@@ -196,38 +249,8 @@ CrashReportWriter::WriteStackFrame(const StackFrame& frame)
CloseObject();
}
-void
-CrashReportWriter::WriteSysctl(const char* sysctlname, const char* valueName)
-{
- size_t size = 0;
- if (sysctlbyname(sysctlname, nullptr, &size, NULL, 0) >= 0)
- {
- ArrayHolder<char> buffer = new char[size];
- if (sysctlbyname(sysctlname, buffer, &size, NULL, 0) >= 0)
- {
- WriteValue(valueName, buffer);
- }
- else
- {
- TRACE("sysctlbyname(%s) 1 FAILED %s\n", sysctlname, strerror(errno));
- }
- }
- else
- {
- TRACE("sysctlbyname(%s) 2 FAILED %s\n", sysctlname, strerror(errno));
- }
-}
-
-#else // __APPLE__
-
-void
-CrashReportWriter::WriteCrashReport()
-{
-}
-
-#endif // __APPLE__
-
-bool CrashReportWriter::OpenWriter(const char* fileName)
+bool
+CrashReportWriter::OpenWriter(const char* fileName)
{
m_fd = open(fileName, O_WRONLY|O_CREAT|O_TRUNC, 0664);
if (m_fd == -1)
@@ -239,13 +262,15 @@ bool CrashReportWriter::OpenWriter(const char* fileName)
return true;
}
-void CrashReportWriter::CloseWriter()
+void
+CrashReportWriter::CloseWriter()
{
assert(m_indent == JSON_INDENT_VALUE);
Write("\n}\n");
}
-void CrashReportWriter::Write(const std::string& text)
+void
+CrashReportWriter::Write(const std::string& text)
{
if (!DumpWriter::WriteData(m_fd, (void*)text.c_str(), text.length()))
{
@@ -253,19 +278,22 @@ void CrashReportWriter::Write(const std::string& text)
}
}
-void CrashReportWriter::Write(const char* buffer)
+void
+CrashReportWriter::Write(const char* buffer)
{
std::string text(buffer);
Write(text);
}
-void CrashReportWriter::Indent(std::string& text)
+void
+CrashReportWriter::Indent(std::string& text)
{
assert(m_indent >= 0);
text.append(m_indent, ' ');
}
-void CrashReportWriter::WriteSeperator(std::string& text)
+void
+CrashReportWriter::WriteSeperator(std::string& text)
{
if (m_comma)
{
@@ -275,7 +303,8 @@ void CrashReportWriter::WriteSeperator(std::string& text)
Indent(text);
}
-void CrashReportWriter::OpenValue(const char* key, char marker)
+void
+CrashReportWriter::OpenValue(const char* key, char marker)
{
std::string text;
WriteSeperator(text);
@@ -292,7 +321,8 @@ void CrashReportWriter::OpenValue(const char* key, char marker)
Write(text);
}
-void CrashReportWriter::CloseValue(char marker)
+void
+CrashReportWriter::CloseValue(char marker)
{
std::string text;
text.append(1, '\n');
@@ -304,7 +334,8 @@ void CrashReportWriter::CloseValue(char marker)
Write(text);
}
-void CrashReportWriter::WriteValue(const char* key, const char* value)
+void
+CrashReportWriter::WriteValue(const char* key, const char* value)
{
std::string text;
WriteSeperator(text);
@@ -317,41 +348,48 @@ void CrashReportWriter::WriteValue(const char* key, const char* value)
Write(text);
}
-void CrashReportWriter::WriteValueBool(const char* key, bool value)
+void
+CrashReportWriter::WriteValueBool(const char* key, bool value)
{
WriteValue(key, value ? "true" : "false");
}
-void CrashReportWriter::WriteValue32(const char* key, uint32_t value)
+void
+CrashReportWriter::WriteValue32(const char* key, uint32_t value)
{
char buffer[16];
snprintf(buffer, sizeof(buffer), "0x%x", value);
WriteValue(key, buffer);
}
-void CrashReportWriter::WriteValue64(const char* key, uint64_t value)
+void
+CrashReportWriter::WriteValue64(const char* key, uint64_t value)
{
char buffer[32];
snprintf(buffer, sizeof(buffer), "0x%" PRIx64, value);
WriteValue(key, buffer);
}
-void CrashReportWriter::OpenObject(const char* key)
+void
+CrashReportWriter::OpenObject(const char* key)
{
OpenValue(key, '{');
}
-void CrashReportWriter::CloseObject()
+void
+CrashReportWriter::CloseObject()
{
CloseValue('}');
}
-void CrashReportWriter::OpenArray(const char* key)
+void
+CrashReportWriter::OpenArray(const char* key)
{
OpenValue(key, '[');
}
-void CrashReportWriter::CloseArray()
+void
+CrashReportWriter::CloseArray()
{
CloseValue(']');
}
diff --git a/src/coreclr/debug/createdump/crashreportwriter.h b/src/coreclr/debug/createdump/crashreportwriter.h
index ef77bfcac55..e5f0f618d94 100644
--- a/src/coreclr/debug/createdump/crashreportwriter.h
+++ b/src/coreclr/debug/createdump/crashreportwriter.h
@@ -13,6 +13,10 @@ private:
bool m_comma;
CrashInfo& m_crashInfo;
+ // no public copy constructor
+ CrashReportWriter(const CrashReportWriter&) = delete;
+ void operator=(const CrashReportWriter&) = delete;
+
public:
CrashReportWriter(CrashInfo& crashInfo);
virtual ~CrashReportWriter();
@@ -21,9 +25,9 @@ public:
private:
void WriteCrashReport();
#ifdef __APPLE__
- void WriteStackFrame(const StackFrame& frame);
void WriteSysctl(const char* sysctlname, const char* valueName);
#endif
+ void WriteStackFrame(const StackFrame& frame);
void Write(const std::string& text);
void Write(const char* buffer);
void Indent(std::string& text);
diff --git a/src/coreclr/debug/createdump/createdump.h b/src/coreclr/debug/createdump/createdump.h
index 95f63f460e4..f588867c792 100644
--- a/src/coreclr/debug/createdump/createdump.h
+++ b/src/coreclr/debug/createdump/createdump.h
@@ -71,6 +71,8 @@ typedef int T_CONTEXT;
#endif
#include <dirent.h>
#include <fcntl.h>
+#include <dlfcn.h>
+#include <cxxabi.h>
#ifdef __APPLE__
#include <ELF.h>
#else
diff --git a/src/coreclr/debug/createdump/datatarget.h b/src/coreclr/debug/createdump/datatarget.h
index 954ff5328b4..792947bafe2 100644
--- a/src/coreclr/debug/createdump/datatarget.h
+++ b/src/coreclr/debug/createdump/datatarget.h
@@ -9,6 +9,10 @@ private:
LONG m_ref; // reference count
CrashInfo& m_crashInfo;
+ // no public copy constructor
+ DumpDataTarget(const DumpDataTarget&) = delete;
+ void operator=(const DumpDataTarget&) = delete;
+
public:
DumpDataTarget(CrashInfo& crashInfo);
virtual ~DumpDataTarget();
diff --git a/src/coreclr/debug/createdump/dumpwriterelf.cpp b/src/coreclr/debug/createdump/dumpwriterelf.cpp
index 57249d83f7e..afd403212b2 100644
--- a/src/coreclr/debug/createdump/dumpwriterelf.cpp
+++ b/src/coreclr/debug/createdump/dumpwriterelf.cpp
@@ -32,12 +32,10 @@ DumpWriter::WriteDump()
ehdr.e_type = ET_CORE;
ehdr.e_machine = ELF_ARCH;
ehdr.e_version = EV_CURRENT;
- ehdr.e_shoff = sizeof(Ehdr);
- ehdr.e_phoff = sizeof(Ehdr) + sizeof(Shdr);
+ ehdr.e_phoff = sizeof(Ehdr);
ehdr.e_ehsize = sizeof(Ehdr);
ehdr.e_phentsize = sizeof(Phdr);
- ehdr.e_shentsize = sizeof(Shdr);
// The ELF header only allows UINT16 for the number of program
// headers. In a core dump this equates to PT_NODE and PT_LOAD.
@@ -60,26 +58,33 @@ DumpWriter::WriteDump()
}
else {
ehdr.e_phnum = PH_HDR_CANARY;
+ ehdr.e_phoff = sizeof(Ehdr) + sizeof(Shdr);
+ ehdr.e_shnum = 1;
+ ehdr.e_shoff = sizeof(Ehdr);
+ ehdr.e_shentsize = sizeof(Shdr);
}
if (!WriteData(&ehdr, sizeof(Ehdr))) {
return false;
}
- size_t offset = sizeof(Ehdr) + sizeof(Shdr) + (phnum * sizeof(Phdr));
+ size_t offset = sizeof(Ehdr) + (phnum * sizeof(Phdr));
size_t filesz = GetProcessInfoSize() + GetAuxvInfoSize() + GetThreadInfoSize() + GetNTFileInfoSize();
- // Add single section containing the actual count
- // of the program headers to be written.
- Shdr shdr;
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_info = phnum;
- // When section header offset is present but ehdr section num = 0
- // then is is expected that the sh_size indicates the size of the
- // section array or 1 in our case.
- shdr.sh_size = 1;
- if (!WriteData(&shdr, sizeof(shdr))) {
- return false;
+ if (ehdr.e_phnum == PH_HDR_CANARY)
+ {
+ // Add single section containing the actual count of the program headers to be written.
+ Shdr shdr;
+ memset(&shdr, 0, sizeof(shdr));
+ shdr.sh_info = phnum;
+ shdr.sh_size = 1;
+ offset += sizeof(Shdr);
+
+ // When section header offset is present but ehdr section num = 0 then is is expected that
+ // the sh_size indicates the size of the section array or 1 in our case.
+ if (!WriteData(&shdr, sizeof(shdr))) {
+ return false;
+ }
}
// PT_NOTE header
diff --git a/src/coreclr/debug/createdump/dumpwriterelf.h b/src/coreclr/debug/createdump/dumpwriterelf.h
index ac4dc10fd2f..6da55da2f13 100644
--- a/src/coreclr/debug/createdump/dumpwriterelf.h
+++ b/src/coreclr/debug/createdump/dumpwriterelf.h
@@ -36,6 +36,10 @@ private:
CrashInfo& m_crashInfo;
BYTE m_tempBuffer[0x4000];
+ // no public copy constructor
+ DumpWriter(const DumpWriter&) = delete;
+ void operator=(const DumpWriter&) = delete;
+
public:
DumpWriter(CrashInfo& crashInfo);
virtual ~DumpWriter();
diff --git a/src/coreclr/debug/createdump/dumpwritermacho.h b/src/coreclr/debug/createdump/dumpwritermacho.h
index 6be2aa7742b..704ea084882 100644
--- a/src/coreclr/debug/createdump/dumpwritermacho.h
+++ b/src/coreclr/debug/createdump/dumpwritermacho.h
@@ -30,6 +30,10 @@ private:
std::vector<ThreadCommand> m_threadLoadCommands;
BYTE m_tempBuffer[0x4000];
+ // no public copy constructor
+ DumpWriter(const DumpWriter&) = delete;
+ void operator=(const DumpWriter&) = delete;
+
public:
DumpWriter(CrashInfo& crashInfo);
virtual ~DumpWriter();
diff --git a/src/coreclr/debug/createdump/moduleinfo.h b/src/coreclr/debug/createdump/moduleinfo.h
index f07e50d592f..2876562fba2 100644
--- a/src/coreclr/debug/createdump/moduleinfo.h
+++ b/src/coreclr/debug/createdump/moduleinfo.h
@@ -10,10 +10,27 @@ private:
GUID m_mvid;
std::string m_moduleName;
bool m_isManaged;
+ void* m_module;
+ uint64_t m_localBaseAddress;
+
+ // no public copy constructor
+ ModuleInfo(const ModuleInfo&) = delete;
+ void operator=(const ModuleInfo&) = delete;
+
+ void LoadModule();
public:
+ ModuleInfo() :
+ m_baseAddress(0),
+ m_module(nullptr),
+ m_localBaseAddress(0)
+ {
+ }
+
ModuleInfo(uint64_t baseAddress) :
- m_baseAddress(baseAddress)
+ m_baseAddress(baseAddress),
+ m_module(nullptr),
+ m_localBaseAddress(0)
{
}
@@ -23,23 +40,19 @@ public:
m_imageSize(imageSize),
m_mvid(*mvid),
m_moduleName(moduleName),
- m_isManaged(isManaged)
- {
- }
-
- // copy constructor
- ModuleInfo(const ModuleInfo& moduleInfo) :
- m_baseAddress(moduleInfo.m_baseAddress),
- m_timeStamp(moduleInfo.m_timeStamp),
- m_imageSize(moduleInfo.m_imageSize),
- m_mvid(moduleInfo.m_mvid),
- m_moduleName(moduleInfo.m_moduleName),
- m_isManaged(moduleInfo.m_isManaged)
+ m_isManaged(isManaged),
+ m_module(nullptr),
+ m_localBaseAddress(0)
{
}
~ModuleInfo()
{
+ if (m_module != nullptr)
+ {
+ dlclose(m_module);
+ m_module = nullptr;
+ }
}
inline bool IsManaged() const { return m_isManaged; }
@@ -49,13 +62,5 @@ public:
inline const GUID* Mvid() const { return &m_mvid; }
inline const std::string& ModuleName() const { return m_moduleName; }
- bool operator<(const ModuleInfo& rhs) const
- {
- return m_baseAddress < rhs.m_baseAddress;
- }
-
- void Trace() const
- {
- TRACE("%" PRIA PRIx64 " %s\n", m_baseAddress, m_moduleName.c_str());
- }
+ const char* GetSymbolName(uint64_t address);
};
diff --git a/src/coreclr/debug/createdump/stackframe.h b/src/coreclr/debug/createdump/stackframe.h
index 90db2697b81..75e20d93120 100644
--- a/src/coreclr/debug/createdump/stackframe.h
+++ b/src/coreclr/debug/createdump/stackframe.h
@@ -5,45 +5,75 @@ struct StackFrame
{
private:
uint64_t m_moduleAddress;
- uint64_t m_returnAddress;
+ uint64_t m_instructionPointer;
uint64_t m_stackPointer;
uint32_t m_nativeOffset;
uint32_t m_token;
uint32_t m_ilOffset;
+ IXCLRDataMethodInstance* m_pMethod;
bool m_isManaged;
public:
// Create native stack frame
- StackFrame(uint64_t moduleAddress, uint64_t returnAddress, uint64_t stackPointer, uint32_t nativeOffset) :
+ StackFrame(uint64_t moduleAddress, uint64_t instructionPointer, uint64_t stackPointer, uint32_t nativeOffset) :
m_moduleAddress(moduleAddress),
- m_returnAddress(returnAddress),
+ m_instructionPointer(instructionPointer),
m_stackPointer(stackPointer),
m_nativeOffset(nativeOffset),
m_token(0),
m_ilOffset(0),
+ m_pMethod(nullptr),
m_isManaged(false)
{
}
// Create managed stack frame
- StackFrame(uint64_t moduleAddress, uint64_t returnAddress, uint64_t stackPointer, uint32_t nativeOffset, uint64_t token, uint32_t ilOffset) :
+ StackFrame(uint64_t moduleAddress, uint64_t instructionPointer, uint64_t stackPointer, IXCLRDataMethodInstance* pMethod, uint32_t nativeOffset, uint64_t token, uint32_t ilOffset) :
m_moduleAddress(moduleAddress),
- m_returnAddress(returnAddress),
+ m_instructionPointer(instructionPointer),
m_stackPointer(stackPointer),
m_nativeOffset(nativeOffset),
m_token(token),
m_ilOffset(ilOffset),
+ m_pMethod(pMethod),
m_isManaged(true)
{
}
+ // copy constructor
+ StackFrame(const StackFrame& frame) :
+ m_moduleAddress(frame.m_moduleAddress),
+ m_instructionPointer(frame.m_instructionPointer),
+ m_stackPointer(frame.m_stackPointer),
+ m_nativeOffset(frame.m_nativeOffset),
+ m_token(frame.m_token),
+ m_ilOffset(frame.m_ilOffset),
+ m_pMethod(frame.m_pMethod),
+ m_isManaged(frame.m_isManaged)
+ {
+ if (m_pMethod != nullptr)
+ {
+ m_pMethod->AddRef();
+ }
+ }
+
+ ~StackFrame()
+ {
+ if (m_pMethod != nullptr)
+ {
+ m_pMethod->Release();
+ m_pMethod = nullptr;
+ }
+ }
+
inline uint64_t ModuleAddress() const { return m_moduleAddress; }
- inline uint64_t ReturnAddress() const { return m_returnAddress; }
+ inline uint64_t InstructionPointer() const { return m_instructionPointer; }
inline uint64_t StackPointer() const { return m_stackPointer; }
inline uint32_t NativeOffset() const { return m_nativeOffset; }
inline uint32_t Token() const { return m_token; }
inline uint32_t ILOffset() const { return m_ilOffset; }
inline bool IsManaged() const { return m_isManaged; }
+ inline IXCLRDataMethodInstance* GetMethod() const { return m_pMethod; }
bool operator<(const StackFrame& rhs) const
{
diff --git a/src/coreclr/debug/createdump/threadinfo.cpp b/src/coreclr/debug/createdump/threadinfo.cpp
index 99284ed0402..2107c6c1baf 100644
--- a/src/coreclr/debug/createdump/threadinfo.cpp
+++ b/src/coreclr/debug/createdump/threadinfo.cpp
@@ -107,7 +107,7 @@ ThreadInfo::UnwindNativeFrames(CONTEXT* pContext)
}
bool
-ThreadInfo::UnwindThread(IXCLRDataProcess* pClrDataProcess)
+ThreadInfo::UnwindThread(IXCLRDataProcess* pClrDataProcess, ISOSDacInterface* pSos)
{
TRACE("Unwind: thread %04x\n", Tid());
@@ -152,7 +152,15 @@ ThreadInfo::UnwindThread(IXCLRDataProcess* pClrDataProcess)
if (SUCCEEDED(pExceptionValue->GetAddress(&exceptionObject)))
{
m_exceptionObject = exceptionObject;
- TRACE("Unwind: exception object %p\n", (void*)exceptionObject);
+ if (pSos != nullptr)
+ {
+ DacpExceptionObjectData exceptionData;
+ if (SUCCEEDED(exceptionData.Request(pSos, exceptionObject)))
+ {
+ m_exceptionHResult = exceptionData.HResult;
+ }
+ }
+ TRACE("Unwind: exception object %p exception hresult %08x\n", (void*)m_exceptionObject, m_exceptionHResult);
}
ReleaseHolder<IXCLRDataTypeInstance> pExceptionType;
if (SUCCEEDED(pExceptionValue->GetType(&pExceptionType)))
@@ -202,6 +210,7 @@ ThreadInfo::GatherStackFrames(CONTEXT* pContext, IXCLRDataStackWalk* pStackwalk)
mdMethodDef token = 0;
uint32_t nativeOffset = 0;
uint32_t ilOffset = 0;
+ ReleaseHolder<IXCLRDataMethodInstance> pMethod;
ReleaseHolder<IXCLRDataFrame> pFrame;
if (SUCCEEDED(pStackwalk->GetFrame(&pFrame)))
@@ -212,7 +221,6 @@ ThreadInfo::GatherStackFrames(CONTEXT* pContext, IXCLRDataStackWalk* pStackwalk)
if ((simpleType & (CLRDATA_SIMPFRAME_MANAGED_METHOD | CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE)) != 0)
{
- ReleaseHolder<IXCLRDataMethodInstance> pMethod;
if (SUCCEEDED(pFrame->GetMethodInstance(&pMethod)))
{
ReleaseHolder<IXCLRDataModule> pModule;
@@ -258,7 +266,7 @@ ThreadInfo::GatherStackFrames(CONTEXT* pContext, IXCLRDataStackWalk* pStackwalk)
}
// Add managed stack frame for the crash info notes
- StackFrame frame(moduleAddress, ip, sp, nativeOffset, token, ilOffset);
+ StackFrame frame(moduleAddress, ip, sp, pMethod.Detach(), nativeOffset, token, ilOffset);
AddStackFrame(frame);
}
@@ -270,7 +278,7 @@ ThreadInfo::AddStackFrame(const StackFrame& frame)
{
TRACE("Unwind: sp %p ip %p off %08x mod %p%c\n",
(void*)frame.StackPointer(),
- (void*)frame.ReturnAddress(),
+ (void*)frame.InstructionPointer(),
frame.NativeOffset(),
(void*)frame.ModuleAddress(),
frame.IsManaged() ? '*' : ' ');
diff --git a/src/coreclr/debug/createdump/threadinfo.h b/src/coreclr/debug/createdump/threadinfo.h
index 1a690157908..7ce0df5f1ec 100644
--- a/src/coreclr/debug/createdump/threadinfo.h
+++ b/src/coreclr/debug/createdump/threadinfo.h
@@ -42,7 +42,8 @@ private:
pid_t m_tgid; // thread group
bool m_managed; // if true, thread has managed code running
uint64_t m_exceptionObject; // exception object address
- std::string m_exceptionType; // exception type
+ std::string m_exceptionType; // exception type
+ int32_t m_exceptionHResult; // exception HRESULT
std::set<StackFrame> m_frames; // stack frames
#ifdef __APPLE__
@@ -64,6 +65,10 @@ private:
#endif
#endif // __APPLE__
+ // no public copy constructor
+ ThreadInfo(const ThreadInfo&) = delete;
+ void operator=(const ThreadInfo&) = delete;
+
public:
#ifdef __APPLE__
ThreadInfo(CrashInfo& crashInfo, pid_t tid, mach_port_t port);
@@ -73,7 +78,7 @@ public:
#endif
~ThreadInfo();
bool Initialize();
- bool UnwindThread(IXCLRDataProcess* pClrDataProcess);
+ bool UnwindThread(IXCLRDataProcess* pClrDataProcess, ISOSDacInterface* pSos);
void GetThreadStack();
void GetThreadContext(uint32_t flags, CONTEXT* context) const;
@@ -83,6 +88,7 @@ public:
inline bool IsManaged() const { return m_managed; }
inline uint64_t ManagedExceptionObject() const { return m_exceptionObject; }
+ inline int32_t ManagedExceptionHResult() const { return m_exceptionHResult; }
inline std::string ManagedExceptionType() const { return m_exceptionType; }
inline const std::set<StackFrame> StackFrames() const { return m_frames; }
@@ -108,16 +114,19 @@ public:
#elif defined(__arm__) && defined(__VFP_FP__) && !defined(__SOFTFP__)
inline const user_vfpregs_struct* VFPRegisters() const { return &m_vfpRegisters; }
#endif
- inline const uint64_t GetStackPointer() const
- {
#if defined(__x86_64__)
- return m_gpRegisters.rsp;
+ inline const uint64_t GetInstructionPointer() const { return m_gpRegisters.rip; }
+ inline const uint64_t GetStackPointer() const { return m_gpRegisters.rsp; }
+ inline const uint64_t GetFramePointer() const { return m_gpRegisters.rbp; }
#elif defined(__aarch64__)
- return MCREG_Sp(m_gpRegisters);
+ inline const uint64_t GetInstructionPointer() const { return MCREG_Pc(m_gpRegisters); }
+ inline const uint64_t GetStackPointer() const { return MCREG_Sp(m_gpRegisters); }
+ inline const uint64_t GetFramePointer() const { return MCREG_Fp(m_gpRegisters); }
#elif defined(__arm__)
- return m_gpRegisters.ARM_sp;
+ inline const uint64_t GetInstructionPointer() const { return m_gpRegisters.ARM_pc; }
+ inline const uint64_t GetStackPointer() const { return m_gpRegisters.ARM_sp; }
+ inline const uint64_t GetFramePointer() const { return m_gpRegisters.ARM_fp; }
#endif
- }
#endif // __APPLE__
private:
diff --git a/src/coreclr/debug/createdump/threadinfomac.cpp b/src/coreclr/debug/createdump/threadinfomac.cpp
index 3ea9151a649..92b9339088f 100644
--- a/src/coreclr/debug/createdump/threadinfomac.cpp
+++ b/src/coreclr/debug/createdump/threadinfomac.cpp
@@ -8,6 +8,7 @@ ThreadInfo::ThreadInfo(CrashInfo& crashInfo, pid_t tid, mach_port_t port) :
m_tid(tid),
m_managed(false),
m_exceptionObject(0),
+ m_exceptionHResult(0),
m_port(port)
{
}
diff --git a/src/coreclr/debug/createdump/threadinfounix.cpp b/src/coreclr/debug/createdump/threadinfounix.cpp
index c1e5ca1154c..90a4c8ab9ff 100644
--- a/src/coreclr/debug/createdump/threadinfounix.cpp
+++ b/src/coreclr/debug/createdump/threadinfounix.cpp
@@ -26,7 +26,8 @@ ThreadInfo::ThreadInfo(CrashInfo& crashInfo, pid_t tid) :
m_crashInfo(crashInfo),
m_tid(tid),
m_managed(false),
- m_exceptionObject(0)
+ m_exceptionObject(0),
+ m_exceptionHResult(0)
{
}
diff --git a/src/coreclr/debug/daccess/task.cpp b/src/coreclr/debug/daccess/task.cpp
index b16f85d8773..c3143bf243b 100644
--- a/src/coreclr/debug/daccess/task.cpp
+++ b/src/coreclr/debug/daccess/task.cpp
@@ -2503,7 +2503,16 @@ ClrDataModule::GetFlags(
{
(*flags) |= CLRDATA_MODULE_IS_MEMORY_STREAM;
}
-
+ PTR_Assembly pAssembly = m_module->GetAssembly();
+ PTR_BaseDomain pBaseDomain = pAssembly->GetDomain();
+ if (pBaseDomain->IsAppDomain())
+ {
+ AppDomain* pAppDomain = pBaseDomain->AsAppDomain();
+ if (pAssembly == pAppDomain->GetRootAssembly())
+ {
+ (*flags) |= CLRDATA_MODULE_IS_MAIN_MODULE;
+ }
+ }
status = S_OK;
}
EX_CATCH
diff --git a/src/coreclr/inc/xclrdata.idl b/src/coreclr/inc/xclrdata.idl
index 818915a29cc..aeddf9529be 100644
--- a/src/coreclr/inc/xclrdata.idl
+++ b/src/coreclr/inc/xclrdata.idl
@@ -1014,6 +1014,7 @@ typedef enum
CLRDATA_MODULE_DEFAULT = 0x00000000,
CLRDATA_MODULE_IS_DYNAMIC = 0x00000001,
CLRDATA_MODULE_IS_MEMORY_STREAM = 0x00000002,
+ CLRDATA_MODULE_IS_MAIN_MODULE = 0x00000004,
} CLRDataModuleFlag;
typedef enum
diff --git a/src/coreclr/pal/prebuilt/inc/xclrdata.h b/src/coreclr/pal/prebuilt/inc/xclrdata.h
index dbee62b9b12..b28463dc86c 100644
--- a/src/coreclr/pal/prebuilt/inc/xclrdata.h
+++ b/src/coreclr/pal/prebuilt/inc/xclrdata.h
@@ -3300,7 +3300,8 @@ enum __MIDL___MIDL_itf_xclrdata_0000_0008_0001
{
CLRDATA_MODULE_DEFAULT = 0,
CLRDATA_MODULE_IS_DYNAMIC = 0x1,
- CLRDATA_MODULE_IS_MEMORY_STREAM = 0x2
+ CLRDATA_MODULE_IS_MEMORY_STREAM = 0x2,
+ CLRDATA_MODULE_IS_MAIN_MODULE = 0x4
} CLRDataModuleFlag;
typedef /* [public][public][public] */