summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/unittests/Process/minidump/CMakeLists.txt1
-rw-r--r--lldb/unittests/Process/minidump/MinidumpParserTest.cpp207
-rw-r--r--lldb/unittests/Process/minidump/RegisterContextMinidumpTest.cpp145
3 files changed, 230 insertions, 123 deletions
diff --git a/lldb/unittests/Process/minidump/CMakeLists.txt b/lldb/unittests/Process/minidump/CMakeLists.txt
index 84071099bb7..699c7984490 100644
--- a/lldb/unittests/Process/minidump/CMakeLists.txt
+++ b/lldb/unittests/Process/minidump/CMakeLists.txt
@@ -1,5 +1,6 @@
add_lldb_unittest(LLDBMinidumpTests
MinidumpParserTest.cpp
+ RegisterContextMinidumpTest.cpp
LINK_LIBS
lldbCore
diff --git a/lldb/unittests/Process/minidump/MinidumpParserTest.cpp b/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
index c87889ed9a0..02480587518 100644
--- a/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
+++ b/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
@@ -6,13 +6,10 @@
//
//===----------------------------------------------------------------------===//
-#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
-#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
#include "Plugins/Process/minidump/MinidumpParser.h"
#include "Plugins/Process/minidump/MinidumpTypes.h"
#include "Plugins/Process/minidump/RegisterContextMinidump_x86_32.h"
#include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
-
#include "TestingSupport/TestUtilities.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Target/MemoryRegionInfo.h"
@@ -490,138 +487,102 @@ TEST_F(MinidumpParserTest, GetModuleListWow64) {
#define REG_VAL32(x) *(reinterpret_cast<uint32_t *>(x))
#define REG_VAL64(x) *(reinterpret_cast<uint64_t *>(x))
-TEST_F(MinidumpParserTest, ConvertMinidumpContext_x86_32) {
+TEST_F(MinidumpParserTest, GetThreadContext_x86_32) {
SetUpData("linux-i386.dmp");
llvm::ArrayRef<MinidumpThread> thread_list = parser->GetThreads();
const MinidumpThread thread = thread_list[0];
llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread));
-
- ArchSpec arch = parser->GetArchitecture();
- auto reg_interface = llvm::make_unique<RegisterContextLinux_i386>(arch);
- lldb::DataBufferSP buf =
- ConvertMinidumpContext_x86_32(registers, reg_interface.get());
- ASSERT_EQ(reg_interface->GetGPRSize(), buf->GetByteSize());
-
- const RegisterInfo *reg_info = reg_interface->GetRegisterInfo();
-
- std::map<uint64_t, uint32_t> reg_values;
-
- reg_values[lldb_eax_i386] = 0x00000000;
- reg_values[lldb_ebx_i386] = 0xf7778000;
- reg_values[lldb_ecx_i386] = 0x00000001;
- reg_values[lldb_edx_i386] = 0xff9dd4a3;
- reg_values[lldb_edi_i386] = 0x080482a8;
- reg_values[lldb_esi_i386] = 0xff9dd55c;
- reg_values[lldb_ebp_i386] = 0xff9dd53c;
- reg_values[lldb_esp_i386] = 0xff9dd52c;
- reg_values[lldb_eip_i386] = 0x080482a0;
- reg_values[lldb_eflags_i386] = 0x00010282;
- reg_values[lldb_cs_i386] = 0x00000023;
- reg_values[lldb_fs_i386] = 0x00000000;
- reg_values[lldb_gs_i386] = 0x00000063;
- reg_values[lldb_ss_i386] = 0x0000002b;
- reg_values[lldb_ds_i386] = 0x0000002b;
- reg_values[lldb_es_i386] = 0x0000002b;
-
- for (uint32_t reg_index = 0; reg_index < reg_interface->GetRegisterCount();
- ++reg_index) {
- if (reg_values.find(reg_index) != reg_values.end()) {
- EXPECT_EQ(reg_values[reg_index],
- REG_VAL32(buf->GetBytes() + reg_info[reg_index].byte_offset));
- }
- }
-}
-
-TEST_F(MinidumpParserTest, ConvertMinidumpContext_x86_64) {
+ const MinidumpContext_x86_32 *context;
+ EXPECT_TRUE(consumeObject(registers, context).Success());
+
+ EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)),
+ MinidumpContext_x86_32_Flags::x86_32_Flag |
+ MinidumpContext_x86_32_Flags::Full |
+ MinidumpContext_x86_32_Flags::FloatingPoint);
+
+ EXPECT_EQ(0x00000000u, context->eax);
+ EXPECT_EQ(0xf7778000u, context->ebx);
+ EXPECT_EQ(0x00000001u, context->ecx);
+ EXPECT_EQ(0xff9dd4a3u, context->edx);
+ EXPECT_EQ(0x080482a8u, context->edi);
+ EXPECT_EQ(0xff9dd55cu, context->esi);
+ EXPECT_EQ(0xff9dd53cu, context->ebp);
+ EXPECT_EQ(0xff9dd52cu, context->esp);
+ EXPECT_EQ(0x080482a0u, context->eip);
+ EXPECT_EQ(0x00010282u, context->eflags);
+ EXPECT_EQ(0x0023u, context->cs);
+ EXPECT_EQ(0x0000u, context->fs);
+ EXPECT_EQ(0x0063u, context->gs);
+ EXPECT_EQ(0x002bu, context->ss);
+ EXPECT_EQ(0x002bu, context->ds);
+ EXPECT_EQ(0x002bu, context->es);
+}
+
+TEST_F(MinidumpParserTest, GetThreadContext_x86_64) {
SetUpData("linux-x86_64.dmp");
llvm::ArrayRef<MinidumpThread> thread_list = parser->GetThreads();
const MinidumpThread thread = thread_list[0];
llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread));
-
- ArchSpec arch = parser->GetArchitecture();
- auto reg_interface = llvm::make_unique<RegisterContextLinux_x86_64>(arch);
- lldb::DataBufferSP buf =
- ConvertMinidumpContext_x86_64(registers, reg_interface.get());
- ASSERT_EQ(reg_interface->GetGPRSize(), buf->GetByteSize());
-
- const RegisterInfo *reg_info = reg_interface->GetRegisterInfo();
-
- std::map<uint64_t, uint64_t> reg_values;
-
- reg_values[lldb_rax_x86_64] = 0x0000000000000000;
- reg_values[lldb_rbx_x86_64] = 0x0000000000000000;
- reg_values[lldb_rcx_x86_64] = 0x0000000000000010;
- reg_values[lldb_rdx_x86_64] = 0x0000000000000000;
- reg_values[lldb_rdi_x86_64] = 0x00007ffceb349cf0;
- reg_values[lldb_rsi_x86_64] = 0x0000000000000000;
- reg_values[lldb_rbp_x86_64] = 0x00007ffceb34a210;
- reg_values[lldb_rsp_x86_64] = 0x00007ffceb34a210;
- reg_values[lldb_r8_x86_64] = 0x00007fe9bc1aa9c0;
- reg_values[lldb_r9_x86_64] = 0x0000000000000000;
- reg_values[lldb_r10_x86_64] = 0x00007fe9bc3f16a0;
- reg_values[lldb_r11_x86_64] = 0x0000000000000246;
- reg_values[lldb_r12_x86_64] = 0x0000000000401c92;
- reg_values[lldb_r13_x86_64] = 0x00007ffceb34a430;
- reg_values[lldb_r14_x86_64] = 0x0000000000000000;
- reg_values[lldb_r15_x86_64] = 0x0000000000000000;
- reg_values[lldb_rip_x86_64] = 0x0000000000401dc6;
- reg_values[lldb_rflags_x86_64] = 0x0000000000010206;
- reg_values[lldb_cs_x86_64] = 0x0000000000000033;
- reg_values[lldb_fs_x86_64] = 0x0000000000000000;
- reg_values[lldb_gs_x86_64] = 0x0000000000000000;
- reg_values[lldb_ss_x86_64] = 0x0000000000000000;
- reg_values[lldb_ds_x86_64] = 0x0000000000000000;
- reg_values[lldb_es_x86_64] = 0x0000000000000000;
-
- for (uint32_t reg_index = 0; reg_index < reg_interface->GetRegisterCount();
- ++reg_index) {
- if (reg_values.find(reg_index) != reg_values.end()) {
- EXPECT_EQ(reg_values[reg_index],
- REG_VAL64(buf->GetBytes() + reg_info[reg_index].byte_offset));
- }
- }
-}
-
-TEST_F(MinidumpParserTest, ConvertMinidumpContext_x86_32_wow64) {
+ const MinidumpContext_x86_64 *context;
+ EXPECT_TRUE(consumeObject(registers, context).Success());
+
+ EXPECT_EQ(MinidumpContext_x86_64_Flags(uint32_t(context->context_flags)),
+ MinidumpContext_x86_64_Flags::x86_64_Flag |
+ MinidumpContext_x86_64_Flags::Control |
+ MinidumpContext_x86_64_Flags::FloatingPoint |
+ MinidumpContext_x86_64_Flags::Integer);
+ EXPECT_EQ(0x0000000000000000u, context->rax);
+ EXPECT_EQ(0x0000000000000000u, context->rbx);
+ EXPECT_EQ(0x0000000000000010u, context->rcx);
+ EXPECT_EQ(0x0000000000000000u, context->rdx);
+ EXPECT_EQ(0x00007ffceb349cf0u, context->rdi);
+ EXPECT_EQ(0x0000000000000000u, context->rsi);
+ EXPECT_EQ(0x00007ffceb34a210u, context->rbp);
+ EXPECT_EQ(0x00007ffceb34a210u, context->rsp);
+ EXPECT_EQ(0x00007fe9bc1aa9c0u, context->r8);
+ EXPECT_EQ(0x0000000000000000u, context->r9);
+ EXPECT_EQ(0x00007fe9bc3f16a0u, context->r10);
+ EXPECT_EQ(0x0000000000000246u, context->r11);
+ EXPECT_EQ(0x0000000000401c92u, context->r12);
+ EXPECT_EQ(0x00007ffceb34a430u, context->r13);
+ EXPECT_EQ(0x0000000000000000u, context->r14);
+ EXPECT_EQ(0x0000000000000000u, context->r15);
+ EXPECT_EQ(0x0000000000401dc6u, context->rip);
+ EXPECT_EQ(0x00010206u, context->eflags);
+ EXPECT_EQ(0x0033u, context->cs);
+ EXPECT_EQ(0x0000u, context->ss);
+}
+
+TEST_F(MinidumpParserTest, GetThreadContext_x86_32_wow64) {
SetUpData("fizzbuzz_wow64.dmp");
llvm::ArrayRef<MinidumpThread> thread_list = parser->GetThreads();
const MinidumpThread thread = thread_list[0];
llvm::ArrayRef<uint8_t> registers(parser->GetThreadContextWow64(thread));
-
- ArchSpec arch = parser->GetArchitecture();
- auto reg_interface = llvm::make_unique<RegisterContextLinux_i386>(arch);
- lldb::DataBufferSP buf =
- ConvertMinidumpContext_x86_32(registers, reg_interface.get());
- ASSERT_EQ(reg_interface->GetGPRSize(), buf->GetByteSize());
-
- const RegisterInfo *reg_info = reg_interface->GetRegisterInfo();
-
- std::map<uint64_t, uint32_t> reg_values;
-
- reg_values[lldb_eax_i386] = 0x00000000;
- reg_values[lldb_ebx_i386] = 0x0037f608;
- reg_values[lldb_ecx_i386] = 0x00e61578;
- reg_values[lldb_edx_i386] = 0x00000008;
- reg_values[lldb_edi_i386] = 0x00000000;
- reg_values[lldb_esi_i386] = 0x00000002;
- reg_values[lldb_ebp_i386] = 0x0037f654;
- reg_values[lldb_esp_i386] = 0x0037f5b8;
- reg_values[lldb_eip_i386] = 0x77ce01fd;
- reg_values[lldb_eflags_i386] = 0x00000246;
- reg_values[lldb_cs_i386] = 0x00000023;
- reg_values[lldb_fs_i386] = 0x00000053;
- reg_values[lldb_gs_i386] = 0x0000002b;
- reg_values[lldb_ss_i386] = 0x0000002b;
- reg_values[lldb_ds_i386] = 0x0000002b;
- reg_values[lldb_es_i386] = 0x0000002b;
-
- for (uint32_t reg_index = 0; reg_index < reg_interface->GetRegisterCount();
- ++reg_index) {
- if (reg_values.find(reg_index) != reg_values.end()) {
- EXPECT_EQ(reg_values[reg_index],
- REG_VAL32(buf->GetBytes() + reg_info[reg_index].byte_offset));
- }
- }
+ const MinidumpContext_x86_32 *context;
+ EXPECT_TRUE(consumeObject(registers, context).Success());
+
+ EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)),
+ MinidumpContext_x86_32_Flags::x86_32_Flag |
+ MinidumpContext_x86_32_Flags::Full |
+ MinidumpContext_x86_32_Flags::FloatingPoint |
+ MinidumpContext_x86_32_Flags::ExtendedRegisters);
+
+ EXPECT_EQ(0x00000000u, context->eax);
+ EXPECT_EQ(0x0037f608u, context->ebx);
+ EXPECT_EQ(0x00e61578u, context->ecx);
+ EXPECT_EQ(0x00000008u, context->edx);
+ EXPECT_EQ(0x00000000u, context->edi);
+ EXPECT_EQ(0x00000002u, context->esi);
+ EXPECT_EQ(0x0037f654u, context->ebp);
+ EXPECT_EQ(0x0037f5b8u, context->esp);
+ EXPECT_EQ(0x77ce01fdu, context->eip);
+ EXPECT_EQ(0x00000246u, context->eflags);
+ EXPECT_EQ(0x0023u, context->cs);
+ EXPECT_EQ(0x0053u, context->fs);
+ EXPECT_EQ(0x002bu, context->gs);
+ EXPECT_EQ(0x002bu, context->ss);
+ EXPECT_EQ(0x002bu, context->ds);
+ EXPECT_EQ(0x002bu, context->es);
}
TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMinAddress) {
diff --git a/lldb/unittests/Process/minidump/RegisterContextMinidumpTest.cpp b/lldb/unittests/Process/minidump/RegisterContextMinidumpTest.cpp
new file mode 100644
index 00000000000..adc65d4f88d
--- /dev/null
+++ b/lldb/unittests/Process/minidump/RegisterContextMinidumpTest.cpp
@@ -0,0 +1,145 @@
+//===-- RegisterContextMinidumpTest.cpp -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
+#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
+#include "Plugins/Process/minidump/RegisterContextMinidump_x86_32.h"
+#include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
+#include "lldb/Utility/DataBuffer.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace lldb_private::minidump;
+
+static uint32_t reg32(const DataBuffer &Buf, const RegisterInfo &Info) {
+ return *reinterpret_cast<const uint32_t *>(Buf.GetBytes() + Info.byte_offset);
+}
+
+static uint64_t reg64(const DataBuffer &Buf, const RegisterInfo &Info) {
+ return *reinterpret_cast<const uint64_t *>(Buf.GetBytes() + Info.byte_offset);
+}
+
+TEST(RegisterContextMinidump, ConvertMinidumpContext_x86_32) {
+ MinidumpContext_x86_32 Context;
+ Context.context_flags =
+ static_cast<uint32_t>(MinidumpContext_x86_32_Flags::x86_32_Flag |
+ MinidumpContext_x86_32_Flags::Control |
+ MinidumpContext_x86_32_Flags::Segments |
+ MinidumpContext_x86_32_Flags::Integer);
+ Context.eax = 0x00010203;
+ Context.ebx = 0x04050607;
+ Context.ecx = 0x08090a0b;
+ Context.edx = 0x0c0d0e0f;
+ Context.edi = 0x10111213;
+ Context.esi = 0x14151617;
+ Context.ebp = 0x18191a1b;
+ Context.esp = 0x1c1d1e1f;
+ Context.eip = 0x20212223;
+ Context.eflags = 0x24252627;
+ Context.cs = 0x2829;
+ Context.fs = 0x2a2b;
+ Context.gs = 0x2c2d;
+ Context.ss = 0x2e2f;
+ Context.ds = 0x3031;
+ Context.es = 0x3233;
+ llvm::ArrayRef<uint8_t> ContextRef(reinterpret_cast<uint8_t *>(&Context),
+ sizeof(Context));
+
+ ArchSpec arch("i386-pc-linux");
+ auto RegInterface = llvm::make_unique<RegisterContextLinux_i386>(arch);
+ lldb::DataBufferSP Buf =
+ ConvertMinidumpContext_x86_32(ContextRef, RegInterface.get());
+ ASSERT_EQ(RegInterface->GetGPRSize(), Buf->GetByteSize());
+
+ const RegisterInfo *Info = RegInterface->GetRegisterInfo();
+ ASSERT_NE(nullptr, Info);
+
+ EXPECT_EQ(Context.eax, reg32(*Buf, Info[lldb_eax_i386]));
+ EXPECT_EQ(Context.ebx, reg32(*Buf, Info[lldb_ebx_i386]));
+ EXPECT_EQ(Context.ecx, reg32(*Buf, Info[lldb_ecx_i386]));
+ EXPECT_EQ(Context.edx, reg32(*Buf, Info[lldb_edx_i386]));
+ EXPECT_EQ(Context.edi, reg32(*Buf, Info[lldb_edi_i386]));
+ EXPECT_EQ(Context.esi, reg32(*Buf, Info[lldb_esi_i386]));
+ EXPECT_EQ(Context.ebp, reg32(*Buf, Info[lldb_ebp_i386]));
+ EXPECT_EQ(Context.esp, reg32(*Buf, Info[lldb_esp_i386]));
+ EXPECT_EQ(Context.eip, reg32(*Buf, Info[lldb_eip_i386]));
+ EXPECT_EQ(Context.eflags, reg32(*Buf, Info[lldb_eflags_i386]));
+ EXPECT_EQ(Context.cs, reg32(*Buf, Info[lldb_cs_i386]));
+ EXPECT_EQ(Context.fs, reg32(*Buf, Info[lldb_fs_i386]));
+ EXPECT_EQ(Context.gs, reg32(*Buf, Info[lldb_gs_i386]));
+ EXPECT_EQ(Context.ss, reg32(*Buf, Info[lldb_ss_i386]));
+ EXPECT_EQ(Context.ds, reg32(*Buf, Info[lldb_ds_i386]));
+ EXPECT_EQ(Context.es, reg32(*Buf, Info[lldb_es_i386]));
+}
+
+TEST(RegisterContextMinidump, ConvertMinidumpContext_x86_64) {
+ MinidumpContext_x86_64 Context;
+ Context.context_flags =
+ static_cast<uint32_t>(MinidumpContext_x86_64_Flags::x86_64_Flag |
+ MinidumpContext_x86_64_Flags::Control |
+ MinidumpContext_x86_64_Flags::Segments |
+ MinidumpContext_x86_64_Flags::Integer);
+ Context.rax = 0x0001020304050607;
+ Context.rbx = 0x08090a0b0c0d0e0f;
+ Context.rcx = 0x1011121314151617;
+ Context.rdx = 0x18191a1b1c1d1e1f;
+ Context.rdi = 0x2021222324252627;
+ Context.rsi = 0x28292a2b2c2d2e2f;
+ Context.rbp = 0x3031323334353637;
+ Context.rsp = 0x38393a3b3c3d3e3f;
+ Context.r8 = 0x4041424344454647;
+ Context.r9 = 0x48494a4b4c4d4e4f;
+ Context.r10 = 0x5051525354555657;
+ Context.r11 = 0x58595a5b5c5d5e5f;
+ Context.r12 = 0x6061626364656667;
+ Context.r13 = 0x68696a6b6c6d6e6f;
+ Context.r14 = 0x7071727374757677;
+ Context.r15 = 0x78797a7b7c7d7e7f;
+ Context.rip = 0x8081828384858687;
+ Context.eflags = 0x88898a8b;
+ Context.cs = 0x8c8d;
+ Context.fs = 0x8e8f;
+ Context.gs = 0x9091;
+ Context.ss = 0x9293;
+ Context.ds = 0x9495;
+ Context.ss = 0x9697;
+ llvm::ArrayRef<uint8_t> ContextRef(reinterpret_cast<uint8_t *>(&Context),
+ sizeof(Context));
+
+ ArchSpec arch("x86_64-pc-linux");
+ auto RegInterface = llvm::make_unique<RegisterContextLinux_x86_64>(arch);
+ lldb::DataBufferSP Buf =
+ ConvertMinidumpContext_x86_64(ContextRef, RegInterface.get());
+ ASSERT_EQ(RegInterface->GetGPRSize(), Buf->GetByteSize());
+
+ const RegisterInfo *Info = RegInterface->GetRegisterInfo();
+ EXPECT_EQ(Context.rax, reg64(*Buf, Info[lldb_rax_x86_64]));
+ EXPECT_EQ(Context.rbx, reg64(*Buf, Info[lldb_rbx_x86_64]));
+ EXPECT_EQ(Context.rcx, reg64(*Buf, Info[lldb_rcx_x86_64]));
+ EXPECT_EQ(Context.rdx, reg64(*Buf, Info[lldb_rdx_x86_64]));
+ EXPECT_EQ(Context.rdi, reg64(*Buf, Info[lldb_rdi_x86_64]));
+ EXPECT_EQ(Context.rsi, reg64(*Buf, Info[lldb_rsi_x86_64]));
+ EXPECT_EQ(Context.rbp, reg64(*Buf, Info[lldb_rbp_x86_64]));
+ EXPECT_EQ(Context.rsp, reg64(*Buf, Info[lldb_rsp_x86_64]));
+ EXPECT_EQ(Context.r8, reg64(*Buf, Info[lldb_r8_x86_64]));
+ EXPECT_EQ(Context.r9, reg64(*Buf, Info[lldb_r9_x86_64]));
+ EXPECT_EQ(Context.r10, reg64(*Buf, Info[lldb_r10_x86_64]));
+ EXPECT_EQ(Context.r11, reg64(*Buf, Info[lldb_r11_x86_64]));
+ EXPECT_EQ(Context.r12, reg64(*Buf, Info[lldb_r12_x86_64]));
+ EXPECT_EQ(Context.r13, reg64(*Buf, Info[lldb_r13_x86_64]));
+ EXPECT_EQ(Context.r14, reg64(*Buf, Info[lldb_r14_x86_64]));
+ EXPECT_EQ(Context.r15, reg64(*Buf, Info[lldb_r15_x86_64]));
+ EXPECT_EQ(Context.rip, reg64(*Buf, Info[lldb_rip_x86_64]));
+ EXPECT_EQ(Context.eflags, reg64(*Buf, Info[lldb_rflags_x86_64]));
+ EXPECT_EQ(Context.cs, reg64(*Buf, Info[lldb_cs_x86_64]));
+ EXPECT_EQ(Context.fs, reg64(*Buf, Info[lldb_fs_x86_64]));
+ EXPECT_EQ(Context.gs, reg64(*Buf, Info[lldb_gs_x86_64]));
+ EXPECT_EQ(Context.ss, reg64(*Buf, Info[lldb_ss_x86_64]));
+ EXPECT_EQ(Context.ds, reg64(*Buf, Info[lldb_ds_x86_64]));
+ EXPECT_EQ(Context.es, reg64(*Buf, Info[lldb_es_x86_64]));
+}
OpenPOWER on IntegriCloud