//---------------------------------------------------------------------- // Disassembler copy constructor //---------------------------------------------------------------------- Disassembler::Disassembler(const ArchSpec& arch, const char *flavor) : m_arch (arch), m_instruction_list(), m_base_addr(LLDB_INVALID_ADDRESS), m_flavor () { if (flavor == NULL) m_flavor.assign("default"); else m_flavor.assign(flavor); // If this is an arm variant that can only include thumb (T16, T32) // instructions, force the arch triple to be "thumbv.." instead of // "armv..." if (arch.GetTriple().getArch() == llvm::Triple::arm && (arch.GetCore() == ArchSpec::Core::eCore_arm_armv7m || arch.GetCore() == ArchSpec::Core::eCore_arm_armv7em || arch.GetCore() == ArchSpec::Core::eCore_arm_armv6m)) { std::string thumb_arch_name (arch.GetTriple().getArchName().str()); // Replace "arm" with "thumb" so we get all thumb variants correct if (thumb_arch_name.size() > 3) { thumb_arch_name.erase(0, 3); thumb_arch_name.insert(0, "thumb"); } m_arch.SetTriple (thumb_arch_name.c_str()); } }
bool lldb_private::operator<(const ArchSpec& lhs, const ArchSpec& rhs) { const ArchSpec::Core lhs_core = lhs.GetCore (); const ArchSpec::Core rhs_core = rhs.GetCore (); return lhs_core < rhs_core; }
bool lldb_private::operator== (const ArchSpec& lhs, const ArchSpec& rhs) { const ArchSpec::Core lhs_core = lhs.GetCore (); const ArchSpec::Core rhs_core = rhs.GetCore (); if (lhs_core == rhs_core) return true; if (lhs_core == ArchSpec::kCore_any || rhs_core == ArchSpec::kCore_any) return true; if (lhs_core == ArchSpec::kCore_arm_any) { if ((rhs_core >= ArchSpec::kCore_arm_first && rhs_core <= ArchSpec::kCore_arm_last) || (rhs_core == ArchSpec::kCore_arm_any)) return true; } else if (rhs_core == ArchSpec::kCore_arm_any) { if ((lhs_core >= ArchSpec::kCore_arm_first && lhs_core <= ArchSpec::kCore_arm_last) || (lhs_core == ArchSpec::kCore_arm_any)) return true; } else if (lhs_core == ArchSpec::kCore_x86_32_any) { if ((rhs_core >= ArchSpec::kCore_x86_32_first && rhs_core <= ArchSpec::kCore_x86_32_last) || (rhs_core == ArchSpec::kCore_x86_32_any)) return true; } else if (rhs_core == ArchSpec::kCore_x86_32_any) { if ((lhs_core >= ArchSpec::kCore_x86_32_first && lhs_core <= ArchSpec::kCore_x86_32_last) || (lhs_core == ArchSpec::kCore_x86_32_any)) return true; } else if (lhs_core == ArchSpec::kCore_ppc_any) { if ((rhs_core >= ArchSpec::kCore_ppc_first && rhs_core <= ArchSpec::kCore_ppc_last) || (rhs_core == ArchSpec::kCore_ppc_any)) return true; } else if (rhs_core == ArchSpec::kCore_ppc_any) { if ((lhs_core >= ArchSpec::kCore_ppc_first && lhs_core <= ArchSpec::kCore_ppc_last) || (lhs_core == ArchSpec::kCore_ppc_any)) return true; } else if (lhs_core == ArchSpec::kCore_ppc64_any) { if ((rhs_core >= ArchSpec::kCore_ppc64_first && rhs_core <= ArchSpec::kCore_ppc64_last) || (rhs_core == ArchSpec::kCore_ppc64_any)) return true; } else if (rhs_core == ArchSpec::kCore_ppc64_any) { if ((lhs_core >= ArchSpec::kCore_ppc64_first && lhs_core <= ArchSpec::kCore_ppc64_last) || (lhs_core == ArchSpec::kCore_ppc64_any)) return true; } return false; }
size_t ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site) { static const uint8_t g_i386_opcode[] = { 0xCC }; ArchSpec arch = GetTarget().GetArchitecture(); const uint8_t *opcode = NULL; size_t opcode_size = 0; switch (arch.GetCore()) { default: assert(false && "CPU type not supported!"); break; case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_64_x86_64: opcode = g_i386_opcode; opcode_size = sizeof(g_i386_opcode); break; } bp_site->SetTrapOpcode(opcode, opcode_size); return opcode_size; }
size_t PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site) { ArchSpec arch = target.GetArchitecture(); const uint8_t *trap_opcode = NULL; size_t trap_opcode_size = 0; switch (arch.GetCore()) { default: assert(false && "Unhandled architecture in PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode()"); break; case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_64_x86_64: { static const uint8_t g_i386_opcode[] = { 0xCC }; trap_opcode = g_i386_opcode; trap_opcode_size = sizeof(g_i386_opcode); } break; } if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) return trap_opcode_size; return 0; }
lldb::RegisterContextSP POSIXThread::GetRegisterContext() { if (!m_reg_context_sp) { ArchSpec arch = Host::GetArchitecture(); switch (arch.GetCore()) { default: assert(false && "CPU type not supported!"); break; case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: case ArchSpec::eCore_x86_32_i486sx: m_reg_context_sp.reset(new RegisterContext_i386(*this, 0)); break; case ArchSpec::eCore_x86_64_x86_64: m_reg_context_sp.reset(new RegisterContext_x86_64(*this, 0)); break; } } return m_reg_context_sp; }
unsigned POSIXThread::GetRegisterIndexFromOffset(unsigned offset) { unsigned reg = LLDB_INVALID_REGNUM; ArchSpec arch = Host::GetArchitecture(); switch (arch.GetCore()) { default: llvm_unreachable("CPU type not supported!"); break; case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: case ArchSpec::eCore_x86_32_i486sx: case ArchSpec::eCore_x86_64_x86_64: { RegisterContextSP base = GetRegisterContext(); if (base) { RegisterContextPOSIX &context = static_cast<RegisterContextPOSIX &>(*base); reg = context.GetRegisterIndexFromOffset(offset); } } break; } return reg; }
lldb::RegisterContextSP POSIXThread::GetRegisterContext() { if (!m_reg_context_sp) { ArchSpec arch = Host::GetArchitecture(); switch (arch.GetCore()) { default: assert(false && "CPU type not supported!"); break; case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: case ArchSpec::eCore_x86_32_i486sx: m_reg_context_sp.reset(new RegisterContext_i386(*this, 0)); break; case ArchSpec::eCore_x86_64_x86_64: // TODO: Use target OS/architecture detection rather than ifdefs so that // lldb built on FreeBSD can debug on Linux and vice-versa. #ifdef __linux__ m_reg_context_sp.reset(new RegisterContextLinux_x86_64(*this, 0)); #endif #ifdef __FreeBSD__ m_reg_context_sp.reset(new RegisterContextFreeBSD_x86_64(*this, 0)); #endif break; } } return m_reg_context_sp; }
unsigned POSIXThread::GetRegisterIndexFromOffset(unsigned offset) { unsigned reg = LLDB_INVALID_REGNUM; ArchSpec arch = Host::GetArchitecture(); switch (arch.GetCore()) { default: llvm_unreachable("CPU type not supported!"); break; case ArchSpec::eCore_mips64: case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: case ArchSpec::eCore_x86_32_i486sx: case ArchSpec::eCore_x86_64_x86_64: { POSIXBreakpointProtocol* reg_ctx = GetPOSIXBreakpointProtocol(); reg = reg_ctx->GetRegisterIndexFromOffset(offset); } break; } return reg; }
Error ELFLinuxPrStatus::Parse(DataExtractor &data, ArchSpec &arch) { Error error; ByteOrder byteorder = data.GetByteOrder(); if (GetSize(arch) > data.GetByteSize()) { error.SetErrorStringWithFormat("NT_PRSTATUS size should be %lu, but the remaining bytes are: %lu", GetSize(arch), data.GetByteSize()); return error; } switch(arch.GetCore()) { case ArchSpec::eCore_s390x_generic: case ArchSpec::eCore_x86_64_x86_64: data.ExtractBytes(0, sizeof(ELFLinuxPrStatus), byteorder, this); break; case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: { // Parsing from a 32 bit ELF core file, and populating/reusing the structure // properly, because the struct is for the 64 bit version offset_t offset = 0; si_signo = data.GetU32(&offset); si_code = data.GetU32(&offset); si_errno = data.GetU32(&offset); pr_cursig = data.GetU16(&offset); offset += 2; // pad pr_sigpend = data.GetU32(&offset); pr_sighold = data.GetU32(&offset); pr_pid = data.GetU32(&offset); pr_ppid = data.GetU32(&offset); pr_pgrp = data.GetU32(&offset); pr_sid = data.GetU32(&offset); pr_utime.tv_sec = data.GetU32(&offset); pr_utime.tv_usec = data.GetU32(&offset); pr_stime.tv_sec = data.GetU32(&offset); pr_stime.tv_usec = data.GetU32(&offset); pr_cutime.tv_sec = data.GetU32(&offset); pr_cutime.tv_usec = data.GetU32(&offset); pr_cstime.tv_sec = data.GetU32(&offset); pr_cstime.tv_usec = data.GetU32(&offset); break; } default: error.SetErrorStringWithFormat("ELFLinuxPrStatus::%s Unknown architecture", __FUNCTION__); break; } return error; }
Error ELFLinuxPrPsInfo::Parse(DataExtractor &data, ArchSpec &arch) { Error error; ByteOrder byteorder = data.GetByteOrder(); if (GetSize(arch) > data.GetByteSize()) { error.SetErrorStringWithFormat("NT_PRPSINFO size should be %lu, but the remaining bytes are: %lu", GetSize(arch), data.GetByteSize()); return error; } switch(arch.GetCore()) { case ArchSpec::eCore_s390x_generic: case ArchSpec::eCore_x86_64_x86_64: data.ExtractBytes(0, sizeof(ELFLinuxPrPsInfo), byteorder, this); break; case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: { // Parsing from a 32 bit ELF core file, and populating/reusing the structure // properly, because the struct is for the 64 bit version size_t size = 0; offset_t offset = 0; pr_state = data.GetU8(&offset); pr_sname = data.GetU8(&offset); pr_zomb = data.GetU8(&offset); pr_nice = data.GetU8(&offset); pr_flag = data.GetU32(&offset); pr_uid = data.GetU16(&offset); pr_gid = data.GetU16(&offset); pr_pid = data.GetU32(&offset); pr_ppid = data.GetU32(&offset); pr_pgrp = data.GetU32(&offset); pr_sid = data.GetU32(&offset); size = 16; data.ExtractBytes(offset, size, byteorder, pr_fname); offset += size; size = 80; data.ExtractBytes(offset, size, byteorder, pr_psargs); offset += size; break; } default: error.SetErrorStringWithFormat("ELFLinuxPrPsInfo::%s Unknown architecture", __FUNCTION__); break; } return error; }
TEST(ArchSpecTest, TestSetTriple) { ArchSpec AS; // Various flavors of valid triples. EXPECT_TRUE(AS.SetTriple("12-10-apple-darwin")); EXPECT_EQ(uint32_t(llvm::MachO::CPU_TYPE_ARM), AS.GetMachOCPUType()); EXPECT_EQ(10u, AS.GetMachOCPUSubType()); EXPECT_TRUE(llvm::StringRef(AS.GetTriple().str()) .consume_front("armv7f-apple-darwin")); EXPECT_EQ(ArchSpec::eCore_arm_armv7f, AS.GetCore()); AS = ArchSpec(); EXPECT_TRUE(AS.SetTriple("18.100-apple-darwin")); EXPECT_EQ(uint32_t(llvm::MachO::CPU_TYPE_POWERPC), AS.GetMachOCPUType()); EXPECT_EQ(100u, AS.GetMachOCPUSubType()); EXPECT_TRUE(llvm::StringRef(AS.GetTriple().str()) .consume_front("powerpc-apple-darwin")); EXPECT_EQ(ArchSpec::eCore_ppc_ppc970, AS.GetCore()); AS = ArchSpec(); EXPECT_TRUE(AS.SetTriple("i686-pc-windows")); EXPECT_EQ(llvm::Triple::x86, AS.GetTriple().getArch()); EXPECT_EQ(llvm::Triple::PC, AS.GetTriple().getVendor()); EXPECT_EQ(llvm::Triple::Win32, AS.GetTriple().getOS()); EXPECT_TRUE( llvm::StringRef(AS.GetTriple().str()).consume_front("i686-pc-windows")); EXPECT_STREQ("i686", AS.GetArchitectureName()); EXPECT_EQ(ArchSpec::eCore_x86_32_i686, AS.GetCore()); // Various flavors of invalid triples. AS = ArchSpec(); EXPECT_FALSE(AS.SetTriple("unknown-unknown-unknown")); AS = ArchSpec(); EXPECT_FALSE(AS.SetTriple("unknown")); AS = ArchSpec(); EXPECT_FALSE(AS.SetTriple("")); }
bool ELFLinuxPrPsInfo::Parse(DataExtractor &data, ArchSpec &arch) { ByteOrder byteorder = data.GetByteOrder(); size_t len; switch(arch.GetCore()) { case ArchSpec::eCore_x86_64_x86_64: len = data.ExtractBytes(0, ELFLINUXPRPSINFO64_SIZE, byteorder, this); return len == ELFLINUXPRPSINFO64_SIZE; default: return false; } }
TEST(ArchSpecTest, MergeFrom) { { ArchSpec A; ArchSpec B("x86_64-pc-linux"); EXPECT_FALSE(A.IsValid()); ASSERT_TRUE(B.IsValid()); EXPECT_EQ(llvm::Triple::ArchType::x86_64, B.GetTriple().getArch()); EXPECT_EQ(llvm::Triple::VendorType::PC, B.GetTriple().getVendor()); EXPECT_EQ(llvm::Triple::OSType::Linux, B.GetTriple().getOS()); EXPECT_EQ(ArchSpec::eCore_x86_64_x86_64, B.GetCore()); A.MergeFrom(B); ASSERT_TRUE(A.IsValid()); EXPECT_EQ(llvm::Triple::ArchType::x86_64, A.GetTriple().getArch()); EXPECT_EQ(llvm::Triple::VendorType::PC, A.GetTriple().getVendor()); EXPECT_EQ(llvm::Triple::OSType::Linux, A.GetTriple().getOS()); EXPECT_EQ(ArchSpec::eCore_x86_64_x86_64, A.GetCore()); } { ArchSpec A("aarch64"); ArchSpec B("aarch64--linux-android"); EXPECT_TRUE(A.IsValid()); EXPECT_TRUE(B.IsValid()); EXPECT_EQ(llvm::Triple::ArchType::aarch64, B.GetTriple().getArch()); EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor, B.GetTriple().getVendor()); EXPECT_EQ(llvm::Triple::OSType::Linux, B.GetTriple().getOS()); EXPECT_EQ(llvm::Triple::EnvironmentType::Android, B.GetTriple().getEnvironment()); A.MergeFrom(B); EXPECT_EQ(llvm::Triple::ArchType::aarch64, A.GetTriple().getArch()); EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor, A.GetTriple().getVendor()); EXPECT_EQ(llvm::Triple::OSType::Linux, A.GetTriple().getOS()); EXPECT_EQ(llvm::Triple::EnvironmentType::Android, A.GetTriple().getEnvironment()); } }
const char * POSIXThread::GetRegisterName(unsigned reg) { const char * name = nullptr; ArchSpec arch = Host::GetArchitecture(); switch (arch.GetCore()) { default: assert(false && "CPU type not supported!"); break; case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: case ArchSpec::eCore_x86_32_i486sx: case ArchSpec::eCore_x86_64_x86_64: name = GetRegisterContext()->GetRegisterName(reg); break; } return name; }
unsigned POSIXThread::GetRegisterIndexFromOffset(unsigned offset) { unsigned reg; ArchSpec arch = Host::GetArchitecture(); switch (arch.GetCore()) { default: assert(false && "CPU type not supported!"); break; case ArchSpec::eCore_x86_32_i386: case ArchSpec::eCore_x86_32_i486: case ArchSpec::eCore_x86_32_i486sx: reg = RegisterContext_i386::GetRegisterIndexFromOffset(offset); break; case ArchSpec::eCore_x86_64_x86_64: reg = RegisterContext_x86_64::GetRegisterIndexFromOffset(offset); break; } return reg; }
DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_string) : Disassembler(arch, flavor_string), m_exe_ctx (NULL), m_inst (NULL), m_data_from_file (false) { if (!FlavorValidForArchSpec (arch, m_flavor.c_str())) { m_flavor.assign("default"); } const char *triple = arch.GetTriple().getTriple().c_str(); unsigned flavor = ~0U; // So far the only supported flavor is "intel" on x86. The base class will set this // correctly coming in. if (arch.GetTriple().getArch() == llvm::Triple::x86 || arch.GetTriple().getArch() == llvm::Triple::x86_64) { if (m_flavor == "intel") { flavor = 1; } else if (m_flavor == "att") { flavor = 0; } } ArchSpec thumb_arch(arch); if (arch.GetTriple().getArch() == llvm::Triple::arm) { std::string thumb_arch_name (thumb_arch.GetTriple().getArchName().str()); // Replace "arm" with "thumb" so we get all thumb variants correct if (thumb_arch_name.size() > 3) { thumb_arch_name.erase(0,3); thumb_arch_name.insert(0, "thumb"); } else { thumb_arch_name = "thumbv7"; } thumb_arch.GetTriple().setArchName(llvm::StringRef(thumb_arch_name.c_str())); } // Cortex-M3 devices (e.g. armv7m) can only execute thumb (T2) instructions, // so hardcode the primary disassembler to thumb mode. Same for Cortex-M4 (armv7em). // // Handle the Cortex-M0 (armv6m) the same; the ISA is a subset of the T and T32 // instructions defined in ARMv7-A. if (arch.GetTriple().getArch() == llvm::Triple::arm && (arch.GetCore() == ArchSpec::Core::eCore_arm_armv7m || arch.GetCore() == ArchSpec::Core::eCore_arm_armv7em || arch.GetCore() == ArchSpec::Core::eCore_arm_armv6m)) { triple = thumb_arch.GetTriple().getTriple().c_str(); } m_disasm_ap.reset (new LLVMCDisassembler(triple, flavor, *this)); if (!m_disasm_ap->IsValid()) { // We use m_disasm_ap.get() to tell whether we are valid or not, so if this isn't good for some reason, // we reset it, and then we won't be valid and FindPlugin will fail and we won't get used. m_disasm_ap.reset(); } // For arm CPUs that can execute arm or thumb instructions, also create a thumb instruction disassembler. if (arch.GetTriple().getArch() == llvm::Triple::arm) { std::string thumb_triple(thumb_arch.GetTriple().getTriple()); m_alternate_disasm_ap.reset(new LLVMCDisassembler(thumb_triple.c_str(), flavor, *this)); if (!m_alternate_disasm_ap->IsValid()) { m_disasm_ap.reset(); m_alternate_disasm_ap.reset(); } } }
//---------------------------------------------------------------------- // Process Control //---------------------------------------------------------------------- Error ProcessMachCore::DoLoadCore () { Error error; if (!m_core_module_sp) { error.SetErrorString ("invalid core module"); return error; } ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); if (core_objfile == NULL) { error.SetErrorString ("invalid core object file"); return error; } if (core_objfile->GetNumThreadContexts() == 0) { error.SetErrorString ("core file doesn't contain any LC_THREAD load commands, or the LC_THREAD architecture is not supported in this lldb"); return error; } SectionList *section_list = core_objfile->GetSectionList(); if (section_list == NULL) { error.SetErrorString ("core file has no sections"); return error; } const uint32_t num_sections = section_list->GetNumSections(0); if (num_sections == 0) { error.SetErrorString ("core file has no sections"); return error; } SetCanJIT(false); llvm::MachO::mach_header header; DataExtractor data (&header, sizeof(header), m_core_module_sp->GetArchitecture().GetByteOrder(), m_core_module_sp->GetArchitecture().GetAddressByteSize()); bool ranges_are_sorted = true; addr_t vm_addr = 0; for (uint32_t i=0; i<num_sections; ++i) { Section *section = section_list->GetSectionAtIndex (i).get(); if (section) { lldb::addr_t section_vm_addr = section->GetFileAddress(); FileRange file_range (section->GetFileOffset(), section->GetFileSize()); VMRangeToFileOffset::Entry range_entry (section_vm_addr, section->GetByteSize(), file_range); if (vm_addr > section_vm_addr) ranges_are_sorted = false; vm_addr = section->GetFileAddress(); VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); // printf ("LC_SEGMENT[%u] arange=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), frange=[0x%8.8x - 0x%8.8x)\n", // i, // range_entry.GetRangeBase(), // range_entry.GetRangeEnd(), // range_entry.data.GetRangeBase(), // range_entry.data.GetRangeEnd()); if (last_entry && last_entry->GetRangeEnd() == range_entry.GetRangeBase() && last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase()) { last_entry->SetRangeEnd (range_entry.GetRangeEnd()); last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd()); //puts("combine"); } else { m_core_aranges.Append(range_entry); } // After we have added this section to our m_core_aranges map, // we can check the start of the section to see if it might // contain dyld for user space apps, or the mach kernel file // for kernel cores. if (m_dyld_addr == LLDB_INVALID_ADDRESS) GetDynamicLoaderAddress (section_vm_addr); } } if (!ranges_are_sorted) { m_core_aranges.Sort(); } // Even if the architecture is set in the target, we need to override // it to match the core file which is always single arch. ArchSpec arch (m_core_module_sp->GetArchitecture()); if (arch.GetCore() == ArchSpec::eCore_x86_32_i486) { arch.SetTriple ("i386", m_target.GetPlatform().get()); } if (arch.IsValid()) m_target.SetArchitecture(arch); if (m_dyld_addr == LLDB_INVALID_ADDRESS) { // We need to locate the main executable in the memory ranges // we have in the core file. We already checked the first address // in each memory zone above, so we just need to check each page // except the first page in each range and stop once we have found // our main executable const size_t num_core_aranges = m_core_aranges.GetSize(); for (size_t i=0; i<num_core_aranges && m_dyld_addr == LLDB_INVALID_ADDRESS; ++i) { const VMRangeToFileOffset::Entry *entry = m_core_aranges.GetEntryAtIndex(i); lldb::addr_t section_vm_addr_start = entry->GetRangeBase(); lldb::addr_t section_vm_addr_end = entry->GetRangeEnd(); for (lldb::addr_t section_vm_addr = section_vm_addr_start + 0x1000; section_vm_addr < section_vm_addr_end; section_vm_addr += 0x1000) { if (GetDynamicLoaderAddress (section_vm_addr)) { break; } } } } return error; }
//---------------------------------------------------------------------- // Process Control //---------------------------------------------------------------------- Error ProcessMachCore::DoLoadCore () { Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_PROCESS)); Error error; if (!m_core_module_sp) { error.SetErrorString ("invalid core module"); return error; } ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); if (core_objfile == NULL) { error.SetErrorString ("invalid core object file"); return error; } if (core_objfile->GetNumThreadContexts() == 0) { error.SetErrorString ("core file doesn't contain any LC_THREAD load commands, or the LC_THREAD architecture is not supported in this lldb"); return error; } SectionList *section_list = core_objfile->GetSectionList(); if (section_list == NULL) { error.SetErrorString ("core file has no sections"); return error; } const uint32_t num_sections = section_list->GetNumSections(0); if (num_sections == 0) { error.SetErrorString ("core file has no sections"); return error; } SetCanJIT(false); llvm::MachO::mach_header header; DataExtractor data (&header, sizeof(header), m_core_module_sp->GetArchitecture().GetByteOrder(), m_core_module_sp->GetArchitecture().GetAddressByteSize()); bool ranges_are_sorted = true; addr_t vm_addr = 0; for (uint32_t i=0; i<num_sections; ++i) { Section *section = section_list->GetSectionAtIndex (i).get(); if (section) { lldb::addr_t section_vm_addr = section->GetFileAddress(); FileRange file_range (section->GetFileOffset(), section->GetFileSize()); VMRangeToFileOffset::Entry range_entry (section_vm_addr, section->GetByteSize(), file_range); if (vm_addr > section_vm_addr) ranges_are_sorted = false; vm_addr = section->GetFileAddress(); VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); // printf ("LC_SEGMENT[%u] arange=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), frange=[0x%8.8x - 0x%8.8x)\n", // i, // range_entry.GetRangeBase(), // range_entry.GetRangeEnd(), // range_entry.data.GetRangeBase(), // range_entry.data.GetRangeEnd()); if (last_entry && last_entry->GetRangeEnd() == range_entry.GetRangeBase() && last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase()) { last_entry->SetRangeEnd (range_entry.GetRangeEnd()); last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd()); //puts("combine"); } else { m_core_aranges.Append(range_entry); } // Some core files don't fill in the permissions correctly. If that is the case // assume read + execute so clients don't think the memory is not readable, // or executable. The memory isn't writable since this plug-in doesn't implement // DoWriteMemory. uint32_t permissions = section->GetPermissions(); if (permissions == 0) permissions = lldb::ePermissionsReadable | lldb::ePermissionsExecutable; m_core_range_infos.Append( VMRangeToPermissions::Entry(section_vm_addr, section->GetByteSize(), permissions)); } } if (!ranges_are_sorted) { m_core_aranges.Sort(); m_core_range_infos.Sort(); } if (m_dyld_addr == LLDB_INVALID_ADDRESS || m_mach_kernel_addr == LLDB_INVALID_ADDRESS) { // We need to locate the main executable in the memory ranges // we have in the core file. We need to search for both a user-process dyld binary // and a kernel binary in memory; we must look at all the pages in the binary so // we don't miss one or the other. Step through all memory segments searching for // a kernel binary and for a user process dyld -- we'll decide which to prefer // later if both are present. const size_t num_core_aranges = m_core_aranges.GetSize(); for (size_t i = 0; i < num_core_aranges; ++i) { const VMRangeToFileOffset::Entry *entry = m_core_aranges.GetEntryAtIndex(i); lldb::addr_t section_vm_addr_start = entry->GetRangeBase(); lldb::addr_t section_vm_addr_end = entry->GetRangeEnd(); for (lldb::addr_t section_vm_addr = section_vm_addr_start; section_vm_addr < section_vm_addr_end; section_vm_addr += 0x1000) { GetDynamicLoaderAddress (section_vm_addr); } } } if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { // In the case of multiple kernel images found in the core file via exhaustive // search, we may not pick the correct one. See if the DynamicLoaderDarwinKernel's // search heuristics might identify the correct one. // Most of the time, I expect the address from SearchForDarwinKernel() will be the // same as the address we found via exhaustive search. if (GetTarget().GetArchitecture().IsValid() == false && m_core_module_sp.get()) { GetTarget().SetArchitecture (m_core_module_sp->GetArchitecture()); } // SearchForDarwinKernel will end up calling back into this this class in the GetImageInfoAddress // method which will give it the m_mach_kernel_addr/m_dyld_addr it already has. Save that aside // and set m_mach_kernel_addr/m_dyld_addr to an invalid address temporarily so // DynamicLoaderDarwinKernel does a real search for the kernel using its own heuristics. addr_t saved_mach_kernel_addr = m_mach_kernel_addr; addr_t saved_user_dyld_addr = m_dyld_addr; m_mach_kernel_addr = LLDB_INVALID_ADDRESS; m_dyld_addr = LLDB_INVALID_ADDRESS; addr_t better_kernel_address = DynamicLoaderDarwinKernel::SearchForDarwinKernel (this); m_mach_kernel_addr = saved_mach_kernel_addr; m_dyld_addr = saved_user_dyld_addr; if (better_kernel_address != LLDB_INVALID_ADDRESS) { if (log) log->Printf ("ProcessMachCore::DoLoadCore: Using the kernel address from DynamicLoaderDarwinKernel"); m_mach_kernel_addr = better_kernel_address; } } // If we found both a user-process dyld and a kernel binary, we need to decide // which to prefer. if (GetCorefilePreference() == eKernelCorefile) { if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { if (log) log->Printf ("ProcessMachCore::DoLoadCore: Using kernel corefile image at 0x%" PRIx64, m_mach_kernel_addr); m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); } else if (m_dyld_addr != LLDB_INVALID_ADDRESS) { if (log) log->Printf ("ProcessMachCore::DoLoadCore: Using user process dyld image at 0x%" PRIx64, m_dyld_addr); m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); } } else { if (m_dyld_addr != LLDB_INVALID_ADDRESS) { if (log) log->Printf ("ProcessMachCore::DoLoadCore: Using user process dyld image at 0x%" PRIx64, m_dyld_addr); m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { if (log) log->Printf ("ProcessMachCore::DoLoadCore: Using kernel corefile image at 0x%" PRIx64, m_mach_kernel_addr); m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); } } if (m_dyld_plugin_name != DynamicLoaderMacOSXDYLD::GetPluginNameStatic()) { // For non-user process core files, the permissions on the core file segments are usually // meaningless, they may be just "read", because we're dealing with kernel coredumps or // early startup coredumps and the dumper is grabbing pages of memory without knowing // what they are. If they aren't marked as "exeuctable", that can break the unwinder // which will check a pc value to see if it is in an executable segment and stop the // backtrace early if it is not ("executable" and "unknown" would both be fine, but // "not executable" will break the unwinder). size_t core_range_infos_size = m_core_range_infos.GetSize(); for (size_t i = 0; i < core_range_infos_size; i++) { VMRangeToPermissions::Entry *ent = m_core_range_infos.GetMutableEntryAtIndex (i); ent->data = lldb::ePermissionsReadable | lldb::ePermissionsExecutable; } } // Even if the architecture is set in the target, we need to override // it to match the core file which is always single arch. ArchSpec arch (m_core_module_sp->GetArchitecture()); if (arch.GetCore() == ArchSpec::eCore_x86_32_i486) { arch.SetTriple ("i386", GetTarget().GetPlatform().get()); } if (arch.IsValid()) GetTarget().SetArchitecture(arch); return error; }
//---------------------------------------------------------------------- // Process Control //---------------------------------------------------------------------- Error ProcessMachCore::DoLoadCore () { Error error; if (!m_core_module_sp) { error.SetErrorString ("invalid core module"); return error; } ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); if (core_objfile == NULL) { error.SetErrorString ("invalid core object file"); return error; } if (core_objfile->GetNumThreadContexts() == 0) { error.SetErrorString ("core file doesn't contain any LC_THREAD load commands, or the LC_THREAD architecture is not supported in this lldb"); return error; } SectionList *section_list = core_objfile->GetSectionList(); if (section_list == NULL) { error.SetErrorString ("core file has no sections"); return error; } const uint32_t num_sections = section_list->GetNumSections(0); if (num_sections == 0) { error.SetErrorString ("core file has no sections"); return error; } SetCanJIT(false); llvm::MachO::mach_header header; DataExtractor data (&header, sizeof(header), m_core_module_sp->GetArchitecture().GetByteOrder(), m_core_module_sp->GetArchitecture().GetAddressByteSize()); bool ranges_are_sorted = true; addr_t vm_addr = 0; for (uint32_t i=0; i<num_sections; ++i) { Section *section = section_list->GetSectionAtIndex (i).get(); if (section) { lldb::addr_t section_vm_addr = section->GetFileAddress(); FileRange file_range (section->GetFileOffset(), section->GetFileSize()); VMRangeToFileOffset::Entry range_entry (section_vm_addr, section->GetByteSize(), file_range); if (vm_addr > section_vm_addr) ranges_are_sorted = false; vm_addr = section->GetFileAddress(); VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back(); // printf ("LC_SEGMENT[%u] arange=[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), frange=[0x%8.8x - 0x%8.8x)\n", // i, // range_entry.GetRangeBase(), // range_entry.GetRangeEnd(), // range_entry.data.GetRangeBase(), // range_entry.data.GetRangeEnd()); if (last_entry && last_entry->GetRangeEnd() == range_entry.GetRangeBase() && last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase()) { last_entry->SetRangeEnd (range_entry.GetRangeEnd()); last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd()); //puts("combine"); } else { m_core_aranges.Append(range_entry); } } } if (!ranges_are_sorted) { m_core_aranges.Sort(); } if (m_dyld_addr == LLDB_INVALID_ADDRESS || m_mach_kernel_addr == LLDB_INVALID_ADDRESS) { // We need to locate the main executable in the memory ranges // we have in the core file. We need to search for both a user-process dyld binary // and a kernel binary in memory; we must look at all the pages in the binary so // we don't miss one or the other. If we find a user-process dyld binary, stop // searching -- that's the one we'll prefer over the mach kernel. const size_t num_core_aranges = m_core_aranges.GetSize(); for (size_t i=0; i<num_core_aranges && m_dyld_addr == LLDB_INVALID_ADDRESS; ++i) { const VMRangeToFileOffset::Entry *entry = m_core_aranges.GetEntryAtIndex(i); lldb::addr_t section_vm_addr_start = entry->GetRangeBase(); lldb::addr_t section_vm_addr_end = entry->GetRangeEnd(); for (lldb::addr_t section_vm_addr = section_vm_addr_start; section_vm_addr < section_vm_addr_end; section_vm_addr += 0x1000) { GetDynamicLoaderAddress (section_vm_addr); } } } // If we found both a user-process dyld and a kernel binary, we need to decide // which to prefer. if (GetCorefilePreference() == eKernelCorefile) { if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); } else if (m_dyld_addr != LLDB_INVALID_ADDRESS) { m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); } } else { if (m_dyld_addr != LLDB_INVALID_ADDRESS) { m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); } } // Even if the architecture is set in the target, we need to override // it to match the core file which is always single arch. ArchSpec arch (m_core_module_sp->GetArchitecture()); if (arch.GetCore() == ArchSpec::eCore_x86_32_i486) { arch.SetTriple ("i386", m_target.GetPlatform().get()); } if (arch.IsValid()) m_target.SetArchitecture(arch); return error; }
bool ArchSpec::Compare (const ArchSpec& rhs, bool exact_match) const { if (GetByteOrder() != rhs.GetByteOrder()) return false; const ArchSpec::Core lhs_core = GetCore (); const ArchSpec::Core rhs_core = rhs.GetCore (); const bool core_match = cores_match (lhs_core, rhs_core, true, exact_match); if (core_match) { const llvm::Triple &lhs_triple = GetTriple(); const llvm::Triple &rhs_triple = rhs.GetTriple(); const llvm::Triple::VendorType lhs_triple_vendor = lhs_triple.getVendor(); const llvm::Triple::VendorType rhs_triple_vendor = rhs_triple.getVendor(); if (lhs_triple_vendor != rhs_triple_vendor) { const bool rhs_vendor_specified = rhs.TripleVendorWasSpecified(); const bool lhs_vendor_specified = TripleVendorWasSpecified(); // Both architectures had the vendor specified, so if they aren't // equal then we return false if (rhs_vendor_specified && lhs_vendor_specified) return false; // Only fail if both vendor types are not unknown if (lhs_triple_vendor != llvm::Triple::UnknownVendor && rhs_triple_vendor != llvm::Triple::UnknownVendor) return false; } const llvm::Triple::OSType lhs_triple_os = lhs_triple.getOS(); const llvm::Triple::OSType rhs_triple_os = rhs_triple.getOS(); if (lhs_triple_os != rhs_triple_os) { const bool rhs_os_specified = rhs.TripleOSWasSpecified(); const bool lhs_os_specified = TripleOSWasSpecified(); // Both architectures had the OS specified, so if they aren't // equal then we return false if (rhs_os_specified && lhs_os_specified) return false; // Only fail if both os types are not unknown if (lhs_triple_os != llvm::Triple::UnknownOS && rhs_triple_os != llvm::Triple::UnknownOS) return false; } const llvm::Triple::EnvironmentType lhs_triple_env = lhs_triple.getEnvironment(); const llvm::Triple::EnvironmentType rhs_triple_env = rhs_triple.getEnvironment(); if (lhs_triple_env != rhs_triple_env) { // Only fail if both environment types are not unknown if (lhs_triple_env != llvm::Triple::UnknownEnvironment && rhs_triple_env != llvm::Triple::UnknownEnvironment) return false; } return true; } return false; }