From c8d82cf6db9148209256e0ed89bdef72aa355d97 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 19 Dec 2012 19:54:20 +0000 Subject: [PATCH] Started adding x86_64 support to Debugger. Stack tracing doesn't work yet, nor does single stepping (somehow manages to completely freeze the system). --- build/jam/Haiku64Image | 4 +- build/jam/OptionalPackages | 2 + src/apps/debugger/Jamfile | 7 + .../arch/x86_64/ArchitectureX8664.cpp | 522 ++++++++++++++++++ .../debugger/arch/x86_64/ArchitectureX8664.h | 90 +++ .../debugger/arch/x86_64/CpuStateX8664.cpp | 146 +++++ src/apps/debugger/arch/x86_64/CpuStateX8664.h | 79 +++ .../arch/x86_64/disasm/DisassemblerX8664.cpp | 111 ++++ .../arch/x86_64/disasm/DisassemblerX8664.h | 42 ++ src/apps/debugger/arch/x86_64/disasm/Jamfile | 16 + .../debugger_interface/DebuggerInterface.cpp | 5 +- src/apps/debugger/elf/ElfFile.cpp | 300 +++++----- src/apps/debugger/elf/ElfFile.h | 8 +- 13 files changed, 1191 insertions(+), 141 deletions(-) create mode 100644 src/apps/debugger/arch/x86_64/ArchitectureX8664.cpp create mode 100644 src/apps/debugger/arch/x86_64/ArchitectureX8664.h create mode 100644 src/apps/debugger/arch/x86_64/CpuStateX8664.cpp create mode 100644 src/apps/debugger/arch/x86_64/CpuStateX8664.h create mode 100644 src/apps/debugger/arch/x86_64/disasm/DisassemblerX8664.cpp create mode 100644 src/apps/debugger/arch/x86_64/disasm/DisassemblerX8664.h create mode 100644 src/apps/debugger/arch/x86_64/disasm/Jamfile diff --git a/build/jam/Haiku64Image b/build/jam/Haiku64Image index abc726e629..7a5e19db21 100644 --- a/build/jam/Haiku64Image +++ b/build/jam/Haiku64Image @@ -23,8 +23,8 @@ SYSTEM_BIN = "[" addattr base64 basename bash beep cal cat catattr checkfs zmore znew ; -SYSTEM_APPS = AboutSystem ActivityMonitor DriveSetup Installer NetworkStatus - ProcessController StyledEdit Terminal +SYSTEM_APPS = AboutSystem ActivityMonitor Debugger DriveSetup Installer + NetworkStatus ProcessController StyledEdit Terminal ; SYSTEM_PREFERENCES = Appearance Backgrounds Deskbar FileTypes diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 4036abc0f1..36324acae2 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -682,6 +682,8 @@ if [ IsOptionalHaikuImagePackageAdded Development ] { : : true ; } } else if $(TARGET_ARCH) = x86_64 { + AddSymlinkToHaikuImage home config settings deskbar Applications + : /boot/system/apps/Debugger : Debugger ; InstallOptionalHaikuImagePackage autoconf-2.69-x86_64-2012-08-17.zip : $(baseURL)/autoconf-2.69-x86_64-2012-08-17.zip diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index b219fe4034..44c56d0a89 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -9,6 +9,7 @@ UsePrivateSystemHeaders ; SEARCH_SOURCE += [ FDirName $(SUBDIR) arch ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) arch x86 ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) arch x86_64 ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) controllers ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_info ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_managers ] ; @@ -71,6 +72,10 @@ Application Debugger : ArchitectureX86.cpp CpuStateX86.cpp + # arch/x86_64 + ArchitectureX8664.cpp + CpuStateX8664.cpp + # controllers DebugReportGenerator.cpp TeamDebugger.cpp @@ -305,6 +310,7 @@ Application Debugger : : Debugger_demangler.o Debugger_disasm_x86.o + Debugger_disasm_x86_64.o Debugger_dwarf.o DebugAnalyzer_gui_table.o @@ -325,5 +331,6 @@ Application Debugger : ; HaikuSubInclude arch x86 disasm ; +HaikuSubInclude arch x86_64 disasm ; HaikuSubInclude demangler ; HaikuSubInclude dwarf ; diff --git a/src/apps/debugger/arch/x86_64/ArchitectureX8664.cpp b/src/apps/debugger/arch/x86_64/ArchitectureX8664.cpp new file mode 100644 index 0000000000..da1d73a3ed --- /dev/null +++ b/src/apps/debugger/arch/x86_64/ArchitectureX8664.cpp @@ -0,0 +1,522 @@ +/* + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2011-2012, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ + + +#include "ArchitectureX8664.h" + +#include + +#include + +#include + +#include "CfaContext.h" +#include "CpuStateX8664.h" +#include "DisassembledCode.h" +#include "FunctionDebugInfo.h" +#include "InstructionInfo.h" +#include "NoOpStackFrameDebugInfo.h" +#include "RegisterMap.h" +#include "StackFrame.h" +#include "Statement.h" +#include "TeamMemory.h" +#include "X86AssemblyLanguage.h" + +#include "disasm/DisassemblerX8664.h" + + +static const int32 kFromDwarfRegisters[] = { + X86_64_REGISTER_RAX, + X86_64_REGISTER_RDX, + X86_64_REGISTER_RCX, + X86_64_REGISTER_RBX, + X86_64_REGISTER_RSI, + X86_64_REGISTER_RDI, + X86_64_REGISTER_RBP, + X86_64_REGISTER_RSP, + X86_64_REGISTER_R8, + X86_64_REGISTER_R9, + X86_64_REGISTER_R10, + X86_64_REGISTER_R11, + X86_64_REGISTER_R12, + X86_64_REGISTER_R13, + X86_64_REGISTER_R14, + X86_64_REGISTER_R15, + -1 + -1, -1, -1, -1, -1, -1, -1, -1, // xmm0-xmm7 + -1, -1, -1, -1, -1, -1, -1, -1, // xmm8-xmm15 + -1, -1, -1, -1, -1, -1, -1, -1, // st0-st7 + -1, -1, -1, -1, -1, -1, -1, -1, // mm0-mm7 + -1, // rflags + X86_64_REGISTER_ES, + X86_64_REGISTER_CS, + X86_64_REGISTER_SS, + X86_64_REGISTER_DS, + X86_64_REGISTER_FS, + X86_64_REGISTER_GS, +}; +static const int32 kFromDwarfRegisterCount = sizeof(kFromDwarfRegisters) / 4; + + +// #pragma mark - ToDwarfRegisterMap + + +struct ArchitectureX8664::ToDwarfRegisterMap : RegisterMap { + ToDwarfRegisterMap() + { + // init the index array from the reverse map + memset(fIndices, -1, sizeof(fIndices)); + for (int32 i = 0; i < kFromDwarfRegisterCount; i++) { + if (kFromDwarfRegisters[i] >= 0) + fIndices[kFromDwarfRegisters[i]] = i; + } + } + + virtual int32 CountRegisters() const + { + return X86_64_REGISTER_COUNT; + } + + virtual int32 MapRegisterIndex(int32 index) const + { + return index >= 0 && index < X86_64_REGISTER_COUNT ? fIndices[index] : -1; + } + +private: + int32 fIndices[X86_64_REGISTER_COUNT]; +}; + + +// #pragma mark - FromDwarfRegisterMap + + +struct ArchitectureX8664::FromDwarfRegisterMap : RegisterMap { + virtual int32 CountRegisters() const + { + return kFromDwarfRegisterCount; + } + + virtual int32 MapRegisterIndex(int32 index) const + { + return index >= 0 && index < kFromDwarfRegisterCount + ? kFromDwarfRegisters[index] : -1; + } +}; + + +// #pragma mark - ArchitectureX8664 + + +ArchitectureX8664::ArchitectureX8664(TeamMemory* teamMemory) + : + Architecture(teamMemory, 8, false), + fAssemblyLanguage(NULL), + fToDwarfRegisterMap(NULL), + fFromDwarfRegisterMap(NULL) +{ +} + + +ArchitectureX8664::~ArchitectureX8664() +{ + if (fToDwarfRegisterMap != NULL) + fToDwarfRegisterMap->ReleaseReference(); + if (fFromDwarfRegisterMap != NULL) + fFromDwarfRegisterMap->ReleaseReference(); + if (fAssemblyLanguage != NULL) + fAssemblyLanguage->ReleaseReference(); +} + + +status_t +ArchitectureX8664::Init() +{ + fAssemblyLanguage = new(std::nothrow) X86AssemblyLanguage; + if (fAssemblyLanguage == NULL) + return B_NO_MEMORY; + + try { + _AddIntegerRegister(X86_64_REGISTER_RIP, "rip", B_UINT64_TYPE, + REGISTER_TYPE_INSTRUCTION_POINTER, false); + _AddIntegerRegister(X86_64_REGISTER_RSP, "rsp", B_UINT64_TYPE, + REGISTER_TYPE_STACK_POINTER, true); + _AddIntegerRegister(X86_64_REGISTER_RBP, "rbp", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, true); + + _AddIntegerRegister(X86_64_REGISTER_RAX, "rax", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, false); + _AddIntegerRegister(X86_64_REGISTER_RBX, "rbx", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_RCX, "rcx", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, false); + _AddIntegerRegister(X86_64_REGISTER_RDX, "rdx", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, false); + + _AddIntegerRegister(X86_64_REGISTER_RSI, "rsi", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_RDI, "rdi", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, true); + + _AddIntegerRegister(X86_64_REGISTER_R8, "r8", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_R9, "r9", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_R10, "r10", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_R11, "r11", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_R12, "r12", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_R13, "r13", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_R14, "r14", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_R15, "r15", B_UINT64_TYPE, + REGISTER_TYPE_GENERAL_PURPOSE, true); + + _AddIntegerRegister(X86_64_REGISTER_CS, "cs", B_UINT16_TYPE, + REGISTER_TYPE_SPECIAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_DS, "ds", B_UINT16_TYPE, + REGISTER_TYPE_SPECIAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_ES, "es", B_UINT16_TYPE, + REGISTER_TYPE_SPECIAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_FS, "fs", B_UINT16_TYPE, + REGISTER_TYPE_SPECIAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_GS, "gs", B_UINT16_TYPE, + REGISTER_TYPE_SPECIAL_PURPOSE, true); + _AddIntegerRegister(X86_64_REGISTER_SS, "ss", B_UINT16_TYPE, + REGISTER_TYPE_SPECIAL_PURPOSE, true); + } catch (std::bad_alloc) { + return B_NO_MEMORY; + } + + fToDwarfRegisterMap = new(std::nothrow) ToDwarfRegisterMap; + fFromDwarfRegisterMap = new(std::nothrow) FromDwarfRegisterMap; + + if (fToDwarfRegisterMap == NULL || fFromDwarfRegisterMap == NULL) + return B_NO_MEMORY; + + return B_OK; +} + + +int32 +ArchitectureX8664::StackGrowthDirection() const +{ + return STACK_GROWTH_DIRECTION_NEGATIVE; +} + + +int32 +ArchitectureX8664::CountRegisters() const +{ + return fRegisters.Count(); +} + + +const Register* +ArchitectureX8664::Registers() const +{ + return fRegisters.Elements(); +} + + +status_t +ArchitectureX8664::InitRegisterRules(CfaContext& context) const +{ + status_t error = Architecture::InitRegisterRules(context); + if (error != B_OK) + return error; + + // set up rule for EIP register + // FIXME: Huh? x86_64's DWARF spec doesn't seem to include RIP in the + // register mapping? Does this matter? + //context.RegisterRule(fToDwarfRegisterMap->MapRegisterIndex( + // X86_REGISTER_EIP))->SetToLocationOffset(-4); + + return B_OK; +} + +status_t +ArchitectureX8664::GetDwarfRegisterMaps(RegisterMap** _toDwarf, + RegisterMap** _fromDwarf) const +{ + if (_toDwarf != NULL) { + *_toDwarf = fToDwarfRegisterMap; + fToDwarfRegisterMap->AcquireReference(); + } + + if (_fromDwarf != NULL) { + *_fromDwarf = fFromDwarfRegisterMap; + fFromDwarfRegisterMap->AcquireReference(); + } + + return B_OK; +} + + +status_t +ArchitectureX8664::CreateCpuState(CpuState*& _state) +{ + CpuStateX8664* state = new(std::nothrow) CpuStateX8664; + if (state == NULL) + return B_NO_MEMORY; + + _state = state; + return B_OK; +} + + +status_t +ArchitectureX8664::CreateCpuState(const void* cpuStateData, size_t size, + CpuState*& _state) +{ + if (size != sizeof(x86_64_debug_cpu_state)) + return B_BAD_VALUE; + + CpuStateX8664* state = new(std::nothrow) CpuStateX8664( + *(const x86_64_debug_cpu_state*)cpuStateData); + if (state == NULL) + return B_NO_MEMORY; + + _state = state; + return B_OK; +} + + +status_t +ArchitectureX8664::CreateStackFrame(Image* image, FunctionDebugInfo* function, + CpuState* _cpuState, bool isTopFrame, StackFrame*& _frame, + CpuState*& _previousCpuState) +{ + fprintf(stderr, "ArchitectureX8664::CreateStackFrame: TODO\n"); + return B_UNSUPPORTED; +} + + +void +ArchitectureX8664::UpdateStackFrameCpuState(const StackFrame* frame, + Image* previousImage, FunctionDebugInfo* previousFunction, + CpuState* previousCpuState) +{ + fprintf(stderr, "ArchitectureX8664::UpdateStackFrameCpuState: TODO\n"); +} + + +status_t +ArchitectureX8664::ReadValueFromMemory(target_addr_t address, uint32 valueType, + BVariant& _value) const +{ + uint8 buffer[64]; + size_t size = BVariant::SizeOfType(valueType); + if (size == 0 || size > sizeof(buffer)) + return B_BAD_VALUE; + + ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, size); + if (bytesRead < 0) + return bytesRead; + if ((size_t)bytesRead != size) + return B_ERROR; + + // TODO: We need to swap endianess, if the host is big endian! + + switch (valueType) { + case B_INT8_TYPE: + _value.SetTo(*(int8*)buffer); + return B_OK; + case B_UINT8_TYPE: + _value.SetTo(*(uint8*)buffer); + return B_OK; + case B_INT16_TYPE: + _value.SetTo(*(int16*)buffer); + return B_OK; + case B_UINT16_TYPE: + _value.SetTo(*(uint16*)buffer); + return B_OK; + case B_INT32_TYPE: + _value.SetTo(*(int32*)buffer); + return B_OK; + case B_UINT32_TYPE: + _value.SetTo(*(uint32*)buffer); + return B_OK; + case B_INT64_TYPE: + _value.SetTo(*(int64*)buffer); + return B_OK; + case B_UINT64_TYPE: + _value.SetTo(*(uint64*)buffer); + return B_OK; + case B_FLOAT_TYPE: + _value.SetTo(*(float*)buffer); + // TODO: float on the host might work differently! + return B_OK; + case B_DOUBLE_TYPE: + _value.SetTo(*(double*)buffer); + // TODO: double on the host might work differently! + return B_OK; + default: + return B_BAD_VALUE; + } +} + + +status_t +ArchitectureX8664::ReadValueFromMemory(target_addr_t addressSpace, + target_addr_t address, uint32 valueType, BVariant& _value) const +{ + // n/a on this architecture + return B_BAD_VALUE; +} + + +status_t +ArchitectureX8664::DisassembleCode(FunctionDebugInfo* function, + const void* buffer, size_t bufferSize, DisassembledCode*& _sourceCode) +{ + DisassembledCode* source = new(std::nothrow) DisassembledCode( + fAssemblyLanguage); + if (source == NULL) + return B_NO_MEMORY; + BReference sourceReference(source, true); + + // init disassembler + DisassemblerX8664 disassembler; + status_t error = disassembler.Init(function->Address(), buffer, bufferSize); + if (error != B_OK) + return error; + + // add a function name line + BString functionName(function->PrettyName()); + if (!source->AddCommentLine((functionName << ':').String())) + return B_NO_MEMORY; + + // disassemble the instructions + BString line; + target_addr_t instructionAddress; + target_size_t instructionSize; + bool breakpointAllowed; + while (disassembler.GetNextInstruction(line, instructionAddress, + instructionSize, breakpointAllowed) == B_OK) { +// TODO: Respect breakpointAllowed! + if (!source->AddInstructionLine(line, instructionAddress, + instructionSize)) { + return B_NO_MEMORY; + } + } + + _sourceCode = sourceReference.Detach(); + return B_OK; +} + + +status_t +ArchitectureX8664::GetStatement(FunctionDebugInfo* function, + target_addr_t address, Statement*& _statement) +{ +// TODO: This is not architecture dependent anymore! + // get the instruction info + InstructionInfo info; + status_t error = GetInstructionInfo(address, info); + if (error != B_OK) + return error; + + // create a statement + ContiguousStatement* statement = new(std::nothrow) ContiguousStatement( + SourceLocation(-1), TargetAddressRange(info.Address(), info.Size())); + if (statement == NULL) + return B_NO_MEMORY; + + _statement = statement; + return B_OK; +} + + +status_t +ArchitectureX8664::GetInstructionInfo(target_addr_t address, + InstructionInfo& _info) +{ + // read the code + uint8 buffer[16]; + // TODO: What's the maximum instruction size? + ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, + sizeof(buffer)); + if (bytesRead < 0) + return bytesRead; + + // init disassembler + DisassemblerX8664 disassembler; + status_t error = disassembler.Init(address, buffer, bytesRead); + if (error != B_OK) + return error; + + // disassemble the instruction + BString line; + target_addr_t instructionAddress; + target_size_t instructionSize; + bool breakpointAllowed; + error = disassembler.GetNextInstruction(line, instructionAddress, + instructionSize, breakpointAllowed); + if (error != B_OK) + return error; + + // FIXME: Is this correct for x86_64? I'm not entirely sure. + instruction_type instructionType = INSTRUCTION_TYPE_OTHER; + if (buffer[0] == 0xff && (buffer[1] & 0x34) == 0x10) { + // absolute call with r/m32 + instructionType = INSTRUCTION_TYPE_SUBROUTINE_CALL; + } else if (buffer[0] == 0xe8 && instructionSize == 5) { + // relative call with rel32 -- don't categorize the call with 0 as + // subroutine call, since it is only used to get the address of the GOT + if (buffer[1] != 0 || buffer[2] != 0 || buffer[3] != 0 + || buffer[4] != 0) { + instructionType = INSTRUCTION_TYPE_SUBROUTINE_CALL; + } + } + + if (!_info.SetTo(instructionAddress, instructionSize, instructionType, + breakpointAllowed, line)) { + return B_NO_MEMORY; + } + + return B_OK; +} + + +status_t +ArchitectureX8664::GetWatchpointDebugCapabilities(int32& _maxRegisterCount, + int32& _maxBytesPerRegister, uint8& _watchpointCapabilityFlags) +{ + // Have 4 debug registers, 1 is required for breakpoint support, which + // leaves 3 available for watchpoints. + _maxRegisterCount = 3; + _maxBytesPerRegister = 8; + + // x86 only supports write and read/write watchpoints. + _watchpointCapabilityFlags = WATCHPOINT_CAPABILITY_FLAG_WRITE + | WATCHPOINT_CAPABILITY_FLAG_READ_WRITE; + + return B_OK; +} + + +void +ArchitectureX8664::_AddRegister(int32 index, const char* name, + uint32 bitSize, uint32 valueType, register_type type, bool calleePreserved) +{ + if (!fRegisters.Add(Register(index, name, bitSize, valueType, type, + calleePreserved))) { + throw std::bad_alloc(); + } +} + + +void +ArchitectureX8664::_AddIntegerRegister(int32 index, const char* name, + uint32 valueType, register_type type, bool calleePreserved) +{ + _AddRegister(index, name, 8 * BVariant::SizeOfType(valueType), valueType, + type, calleePreserved); +} diff --git a/src/apps/debugger/arch/x86_64/ArchitectureX8664.h b/src/apps/debugger/arch/x86_64/ArchitectureX8664.h new file mode 100644 index 0000000000..ec814483f0 --- /dev/null +++ b/src/apps/debugger/arch/x86_64/ArchitectureX8664.h @@ -0,0 +1,90 @@ +/* + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2011-2012, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ +#ifndef ARCHITECTURE_X86_64_H +#define ARCHITECTURE_X86_64_H + + +#include + +#include "Architecture.h" +#include "Register.h" + + +class SourceLanguage; + + +class ArchitectureX8664 : public Architecture { +public: + ArchitectureX8664(TeamMemory* teamMemory); + virtual ~ArchitectureX8664(); + + virtual status_t Init(); + + virtual int32 StackGrowthDirection() const; + + virtual int32 CountRegisters() const; + virtual const Register* Registers() const; + virtual status_t InitRegisterRules(CfaContext& context) const; + + virtual status_t GetDwarfRegisterMaps(RegisterMap** _toDwarf, + RegisterMap** _fromDwarf) const; + + virtual status_t CreateCpuState(CpuState*& _state); + virtual status_t CreateCpuState(const void* cpuStateData, + size_t size, CpuState*& _state); + virtual status_t CreateStackFrame(Image* image, + FunctionDebugInfo* function, + CpuState* cpuState, bool isTopFrame, + StackFrame*& _previousFrame, + CpuState*& _previousCpuState); + virtual void UpdateStackFrameCpuState( + const StackFrame* frame, + Image* previousImage, + FunctionDebugInfo* previousFunction, + CpuState* previousCpuState); + + virtual status_t ReadValueFromMemory(target_addr_t address, + uint32 valueType, BVariant& _value) const; + virtual status_t ReadValueFromMemory(target_addr_t addressSpace, + target_addr_t address, uint32 valueType, + BVariant& _value) const; + + virtual status_t DisassembleCode(FunctionDebugInfo* function, + const void* buffer, size_t bufferSize, + DisassembledCode*& _sourceCode); + virtual status_t GetStatement(FunctionDebugInfo* function, + target_addr_t address, + Statement*& _statement); + virtual status_t GetInstructionInfo(target_addr_t address, + InstructionInfo& _info); + + virtual status_t GetWatchpointDebugCapabilities( + int32& _maxRegisterCount, + int32& _maxBytesPerRegister, + uint8& _watchpointCapabilityFlags); + +private: + struct ToDwarfRegisterMap; + struct FromDwarfRegisterMap; + +private: + void _AddRegister(int32 index, const char* name, + uint32 bitSize, uint32 valueType, + register_type type, bool calleePreserved); + void _AddIntegerRegister(int32 index, + const char* name, uint32 valueType, + register_type type, bool calleePreserved); + +private: + Array fRegisters; + SourceLanguage* fAssemblyLanguage; + ToDwarfRegisterMap* fToDwarfRegisterMap; + FromDwarfRegisterMap* fFromDwarfRegisterMap; +}; + + +#endif // ARCHITECTURE_X86_64_H diff --git a/src/apps/debugger/arch/x86_64/CpuStateX8664.cpp b/src/apps/debugger/arch/x86_64/CpuStateX8664.cpp new file mode 100644 index 0000000000..1d562e02d0 --- /dev/null +++ b/src/apps/debugger/arch/x86_64/CpuStateX8664.cpp @@ -0,0 +1,146 @@ +/* + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2011, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ + +#include "CpuStateX8664.h" + +#include "Register.h" + + +CpuStateX8664::CpuStateX8664() + : + fSetRegisters() +{ +} + + +CpuStateX8664::CpuStateX8664(const x86_64_debug_cpu_state& state) + : + fSetRegisters() +{ + SetIntRegister(X86_64_REGISTER_RIP, state.rip); + SetIntRegister(X86_64_REGISTER_RSP, state.rsp); + SetIntRegister(X86_64_REGISTER_RBP, state.rbp); + SetIntRegister(X86_64_REGISTER_RAX, state.rax); + SetIntRegister(X86_64_REGISTER_RBX, state.rbx); + SetIntRegister(X86_64_REGISTER_RCX, state.rcx); + SetIntRegister(X86_64_REGISTER_RDX, state.rdx); + SetIntRegister(X86_64_REGISTER_RSI, state.rsi); + SetIntRegister(X86_64_REGISTER_RDI, state.rdi); + SetIntRegister(X86_64_REGISTER_R8, state.r8); + SetIntRegister(X86_64_REGISTER_R9, state.r9); + SetIntRegister(X86_64_REGISTER_R10, state.r10); + SetIntRegister(X86_64_REGISTER_R11, state.r11); + SetIntRegister(X86_64_REGISTER_R12, state.r12); + SetIntRegister(X86_64_REGISTER_R13, state.r13); + SetIntRegister(X86_64_REGISTER_R14, state.r14); + SetIntRegister(X86_64_REGISTER_R15, state.r15); + SetIntRegister(X86_64_REGISTER_CS, state.cs); + SetIntRegister(X86_64_REGISTER_DS, state.ds); + SetIntRegister(X86_64_REGISTER_ES, state.es); + SetIntRegister(X86_64_REGISTER_FS, state.fs); + SetIntRegister(X86_64_REGISTER_GS, state.gs); + SetIntRegister(X86_64_REGISTER_SS, state.ss); +} + + +CpuStateX8664::~CpuStateX8664() +{ +} + + +target_addr_t +CpuStateX8664::InstructionPointer() const +{ + return IsRegisterSet(X86_64_REGISTER_RIP) + ? IntRegisterValue(X86_64_REGISTER_RIP) : 0; +} + + +target_addr_t +CpuStateX8664::StackFramePointer() const +{ + return IsRegisterSet(X86_64_REGISTER_RBP) + ? IntRegisterValue(X86_64_REGISTER_RBP) : 0; +} + + +target_addr_t +CpuStateX8664::StackPointer() const +{ + return IsRegisterSet(X86_64_REGISTER_RSP) + ? IntRegisterValue(X86_64_REGISTER_RSP) : 0; +} + + +bool +CpuStateX8664::GetRegisterValue(const Register* reg, BVariant& _value) const +{ + int32 index = reg->Index(); + if (!IsRegisterSet(index)) + return false; + + if (index >= X86_64_INT_REGISTER_END) + return false; + + if (reg->BitSize() == 16) + _value.SetTo((uint16)fIntRegisters[index]); + else + _value.SetTo(fIntRegisters[index]); + + return true; +} + + +bool +CpuStateX8664::SetRegisterValue(const Register* reg, const BVariant& value) +{ + int32 index = reg->Index(); + if (index >= X86_64_INT_REGISTER_END) + return false; + + fIntRegisters[index] = value.ToUInt64(); + fSetRegisters[index] = 1; + return true; +} + + +bool +CpuStateX8664::IsRegisterSet(int32 index) const +{ + return index >= 0 && index < X86_64_REGISTER_COUNT && fSetRegisters[index]; +} + + +uint64 +CpuStateX8664::IntRegisterValue(int32 index) const +{ + if (!IsRegisterSet(index) || index >= X86_64_INT_REGISTER_END) + return 0; + + return fIntRegisters[index]; +} + + +void +CpuStateX8664::SetIntRegister(int32 index, uint64 value) +{ + if (index < 0 || index >= X86_64_INT_REGISTER_END) + return; + + fIntRegisters[index] = value; + fSetRegisters[index] = 1; +} + + +void +CpuStateX8664::UnsetRegister(int32 index) +{ + if (index < 0 || index >= X86_64_REGISTER_COUNT) + return; + + fSetRegisters[index] = 0; +} diff --git a/src/apps/debugger/arch/x86_64/CpuStateX8664.h b/src/apps/debugger/arch/x86_64/CpuStateX8664.h new file mode 100644 index 0000000000..2c52d60b90 --- /dev/null +++ b/src/apps/debugger/arch/x86_64/CpuStateX8664.h @@ -0,0 +1,79 @@ +/* + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2011, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ +#ifndef CPU_STATE_X86_64_H +#define CPU_STATE_X86_64_H + +#include + +#include + +#include "CpuState.h" + + +enum { + X86_64_REGISTER_RIP = 0, + X86_64_REGISTER_RSP, + X86_64_REGISTER_RBP, + + X86_64_REGISTER_RAX, + X86_64_REGISTER_RBX, + X86_64_REGISTER_RCX, + X86_64_REGISTER_RDX, + + X86_64_REGISTER_RSI, + X86_64_REGISTER_RDI, + + X86_64_REGISTER_R8, + X86_64_REGISTER_R9, + X86_64_REGISTER_R10, + X86_64_REGISTER_R11, + X86_64_REGISTER_R12, + X86_64_REGISTER_R13, + X86_64_REGISTER_R14, + X86_64_REGISTER_R15, + + X86_64_REGISTER_CS, + X86_64_REGISTER_DS, + X86_64_REGISTER_ES, + X86_64_REGISTER_FS, + X86_64_REGISTER_GS, + X86_64_REGISTER_SS, + + X86_64_INT_REGISTER_END, + X86_64_REGISTER_COUNT +}; + + +class CpuStateX8664 : public CpuState { +public: + CpuStateX8664(); + CpuStateX8664(const x86_64_debug_cpu_state& state); + virtual ~CpuStateX8664(); + + virtual target_addr_t InstructionPointer() const; + virtual target_addr_t StackFramePointer() const; + virtual target_addr_t StackPointer() const; + virtual bool GetRegisterValue(const Register* reg, + BVariant& _value) const; + virtual bool SetRegisterValue(const Register* reg, + const BVariant& value); + + bool IsRegisterSet(int32 index) const; + uint64 IntRegisterValue(int32 index) const; + void SetIntRegister(int32 index, uint64 value); + void UnsetRegister(int32 index); + +private: + typedef std::bitset RegisterBitSet; + +private: + uint64 fIntRegisters[X86_64_REGISTER_COUNT]; + RegisterBitSet fSetRegisters; +}; + + +#endif // CPU_STATE_X86_64_H diff --git a/src/apps/debugger/arch/x86_64/disasm/DisassemblerX8664.cpp b/src/apps/debugger/arch/x86_64/disasm/DisassemblerX8664.cpp new file mode 100644 index 0000000000..7122943d11 --- /dev/null +++ b/src/apps/debugger/arch/x86_64/disasm/DisassemblerX8664.cpp @@ -0,0 +1,111 @@ +/* + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2008, François Revol, revol@free.fr + * Distributed under the terms of the MIT License. + */ + +#include "DisassemblerX8664.h" + +#include + +#include "udis86.h" + +#include + + +struct DisassemblerX8664::UdisData : ud_t { +}; + + +DisassemblerX8664::DisassemblerX8664() + : + fAddress(0), + fCode(NULL), + fCodeSize(0), + fUdisData(NULL) +{ +} + + +DisassemblerX8664::~DisassemblerX8664() +{ + delete fUdisData; +} + + +status_t +DisassemblerX8664::Init(target_addr_t address, const void* code, size_t codeSize) +{ + // unset old data + delete fUdisData; + fUdisData = NULL; + + // set new data + fUdisData = new(std::nothrow) UdisData; + if (fUdisData == NULL) + return B_NO_MEMORY; + + fAddress = address; + fCode = (const uint8*)code; + fCodeSize = codeSize; + + // init udis + ud_init(fUdisData); + ud_set_input_buffer(fUdisData, (unsigned char*)fCode, fCodeSize); + ud_set_mode(fUdisData, 64); + ud_set_pc(fUdisData, (uint64_t)fAddress); + ud_set_syntax(fUdisData, UD_SYN_ATT); + ud_set_vendor(fUdisData, UD_VENDOR_INTEL); + // TODO: Set the correct vendor! + + return B_OK; +} + + +status_t +DisassemblerX8664::GetNextInstruction(BString& line, target_addr_t& _address, + target_size_t& _size, bool& _breakpointAllowed) +{ + unsigned int size = ud_disassemble(fUdisData); + if (size < 1) + return B_ENTRY_NOT_FOUND; + + uint64 address = ud_insn_off(fUdisData); + + char buffer[256]; + snprintf(buffer, sizeof(buffer), "0x%08" B_PRIx64 ": %16.16s %s", address, + ud_insn_hex(fUdisData), ud_insn_asm(fUdisData)); + // TODO: Resolve symbols! + + line = buffer; + _address = address; + _size = size; + _breakpointAllowed = true; + // TODO: Implement (rep!)! + + return B_OK; +} + + +status_t +DisassemblerX8664::GetPreviousInstruction(target_addr_t nextAddress, + target_addr_t& _address, target_size_t& _size) +{ + if (nextAddress < fAddress || nextAddress > fAddress + fCodeSize) + return B_BAD_VALUE; + + // loop until hitting the last instruction + while (true) { + target_size_t size = ud_disassemble(fUdisData); + if (size < 1) + return B_ENTRY_NOT_FOUND; + + target_addr_t address = ud_insn_off(fUdisData); + if (address + size == nextAddress) { + _address = address; + _size = size; + return B_OK; + } + } +} diff --git a/src/apps/debugger/arch/x86_64/disasm/DisassemblerX8664.h b/src/apps/debugger/arch/x86_64/disasm/DisassemblerX8664.h new file mode 100644 index 0000000000..af045f4b7b --- /dev/null +++ b/src/apps/debugger/arch/x86_64/disasm/DisassemblerX8664.h @@ -0,0 +1,42 @@ +/* + * Copyright 2012, Alex Smith, alex@alex-smith.me.uk. + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef DISASSEMBLER_X86_64_H +#define DISASSEMBLER_X86_64_H + +#include + +#include "Types.h" + + +class DisassemblerX8664 { +public: + DisassemblerX8664(); + virtual ~DisassemblerX8664(); + + virtual status_t Init(target_addr_t address, const void* code, + size_t codeSize); + + virtual status_t GetNextInstruction(BString& line, + target_addr_t& _address, + target_size_t& _size, + bool& _breakpointAllowed); + virtual status_t GetPreviousInstruction( + target_addr_t nextAddress, + target_addr_t& _address, + target_size_t& _size); + +private: + struct UdisData; + +private: + target_addr_t fAddress; + const uint8* fCode; + size_t fCodeSize; + UdisData* fUdisData; +}; + + +#endif // DISASSEMBLER_X86_64_H diff --git a/src/apps/debugger/arch/x86_64/disasm/Jamfile b/src/apps/debugger/arch/x86_64/disasm/Jamfile new file mode 100644 index 0000000000..7abcbb21b7 --- /dev/null +++ b/src/apps/debugger/arch/x86_64/disasm/Jamfile @@ -0,0 +1,16 @@ +SubDir HAIKU_TOP src apps debugger arch x86_64 disasm ; + +CCFLAGS += -Werror ; +C++FLAGS += -Werror ; + +UseHeaders [ LibraryHeaders udis86 ] ; +UseHeaders [ LibraryHeaders [ FDirName udis86 libudis86 ] ] ; + +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ; +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) $(DOTDOT) types ] ; + + +MergeObject Debugger_disasm_x86_64.o + : + DisassemblerX8664.cpp +; diff --git a/src/apps/debugger/debugger_interface/DebuggerInterface.cpp b/src/apps/debugger/debugger_interface/DebuggerInterface.cpp index 8a47162d4b..585327d633 100644 --- a/src/apps/debugger/debugger_interface/DebuggerInterface.cpp +++ b/src/apps/debugger/debugger_interface/DebuggerInterface.cpp @@ -22,6 +22,7 @@ #include "debug_utils.h" #include "ArchitectureX86.h" +#include "ArchitectureX8664.h" #include "CpuState.h" #include "DebugEvent.h" #include "ImageInfo.h" @@ -255,8 +256,10 @@ DebuggerInterface::Init() // TODO: this probably needs to be rethought a bit, // since especially when we eventually support remote debugging, // the architecture will depend on the target machine, not the host -#ifdef ARCH_x86 +#if defined(ARCH_x86) fArchitecture = new(std::nothrow) ArchitectureX86(this); +#elif defined(ARCH_x86_64) + fArchitecture = new(std::nothrow) ArchitectureX8664(this); #else return B_UNSUPPORTED; #endif diff --git a/src/apps/debugger/elf/ElfFile.cpp b/src/apps/debugger/elf/ElfFile.cpp index abf1147861..23294351e4 100644 --- a/src/apps/debugger/elf/ElfFile.cpp +++ b/src/apps/debugger/elf/ElfFile.cpp @@ -107,8 +107,7 @@ ElfSegment::~ElfSegment() ElfFile::ElfFile() : fFileSize(0), - fFD(-1), - fElfHeader(NULL) + fFD(-1) { } @@ -121,8 +120,6 @@ ElfFile::~ElfFile() while (ElfSection* section = fSections.RemoveHead()) delete section; - free(fElfHeader); - if (fFD >= 0) close(fFD); } @@ -146,129 +143,16 @@ ElfFile::Init(const char* fileName) } fFileSize = st.st_size; - // read the elf header - fElfHeader = (Elf32_Ehdr*)malloc(sizeof(Elf32_Ehdr)); - if (fElfHeader == NULL) - return B_NO_MEMORY; - - ssize_t bytesRead = pread(fFD, fElfHeader, sizeof(Elf32_Ehdr), 0); - if (bytesRead != (ssize_t)sizeof(Elf32_Ehdr)) + // Read the identification information to determine the class. + uint8 elfIdent[EI_NIDENT]; + ssize_t bytesRead = pread(fFD, elfIdent, sizeof(elfIdent), 0); + if (bytesRead != (ssize_t)sizeof(elfIdent)) return bytesRead < 0 ? errno : B_ERROR; - // check the ELF header - if (!_CheckRange(0, sizeof(Elf32_Ehdr)) || !_CheckElfHeader()) { - WARNING("\"%s\": Not an ELF file\n", fileName); - return B_BAD_DATA; - } - - // check section header table values - off_t sectionHeadersOffset = fElfHeader->e_shoff; - size_t sectionHeaderSize = fElfHeader->e_shentsize; - int sectionCount = fElfHeader->e_shnum; - size_t sectionHeaderTableSize = sectionHeaderSize * sectionCount; - if (!_CheckRange(sectionHeadersOffset, sectionHeaderTableSize)) { - WARNING("\"%s\": Invalid ELF header\n", fileName); - return B_BAD_DATA; - } - - // read the section header table - uint8* sectionHeaderTable = (uint8*)malloc(sectionHeaderTableSize); - if (sectionHeaderTable == NULL) - return B_NO_MEMORY; - MemoryDeleter sectionHeaderTableDeleter(sectionHeaderTable); - - bytesRead = pread(fFD, sectionHeaderTable, sectionHeaderTableSize, - sectionHeadersOffset); - if (bytesRead != (ssize_t)sectionHeaderTableSize) - return bytesRead < 0 ? errno : B_ERROR; - - // check and get the section header string section - Elf32_Shdr* stringSectionHeader = (Elf32_Shdr*)(sectionHeaderTable - + fElfHeader->e_shstrndx * sectionHeaderSize); - if (!_CheckRange(stringSectionHeader->sh_offset, - stringSectionHeader->sh_size)) { - WARNING("\"%s\": Invalid string section header\n", fileName); - return B_BAD_DATA; - } - size_t sectionStringSize = stringSectionHeader->sh_size; - - ElfSection* sectionStringSection = new(std::nothrow) ElfSection(".shstrtab", - fFD, stringSectionHeader->sh_offset, sectionStringSize, - stringSectionHeader->sh_addr, stringSectionHeader->sh_flags); - if (sectionStringSection == NULL) - return B_NO_MEMORY; - fSections.Add(sectionStringSection); - - status_t error = sectionStringSection->Load(); - if (error != B_OK) - return error; - - const char* sectionStrings = (const char*)sectionStringSection->Data(); - - // read the other sections - for (int i = 0; i < sectionCount; i++) { - Elf32_Shdr* sectionHeader = (Elf32_Shdr*)(sectionHeaderTable - + i * sectionHeaderSize); - // skip invalid sections and the section header string section - const char* name = sectionStrings + sectionHeader->sh_name; - if (sectionHeader->sh_name >= sectionStringSize - || !_CheckRange(sectionHeader->sh_offset, sectionHeader->sh_size) - || i == fElfHeader->e_shstrndx) { - continue; - } - - // create an ElfSection - ElfSection* section = new(std::nothrow) ElfSection(name, fFD, - sectionHeader->sh_offset, sectionHeader->sh_size, - sectionHeader->sh_addr, sectionHeader->sh_flags); - if (section == NULL) - return B_NO_MEMORY; - fSections.Add(section); - } - - // check program header table values - off_t programHeadersOffset = fElfHeader->e_phoff; - size_t programHeaderSize = fElfHeader->e_phentsize; - int segmentCount = fElfHeader->e_phnum; - size_t programHeaderTableSize = programHeaderSize * segmentCount; - if (!_CheckRange(programHeadersOffset, programHeaderTableSize)) { - WARNING("\"%s\": Invalid ELF header\n", fileName); - return B_BAD_DATA; - } - - // read the program header table - uint8* programHeaderTable = (uint8*)malloc(programHeaderTableSize); - if (programHeaderTable == NULL) - return B_NO_MEMORY; - MemoryDeleter programHeaderTableDeleter(programHeaderTable); - - bytesRead = pread(fFD, programHeaderTable, programHeaderTableSize, - programHeadersOffset); - if (bytesRead != (ssize_t)programHeaderTableSize) - return bytesRead < 0 ? errno : B_ERROR; - - // read the program headers and create ElfSegment objects - for (int i = 0; i < segmentCount; i++) { - Elf32_Phdr* programHeader = (Elf32_Phdr*)(programHeaderTable - + i * programHeaderSize); - // skip program headers we aren't interested in or that are invalid - if (programHeader->p_type != PT_LOAD || programHeader->p_filesz == 0 - || programHeader->p_memsz == 0 - || !_CheckRange(programHeader->p_offset, programHeader->p_filesz)) { - continue; - } - - // create an ElfSegment - ElfSegment* segment = new(std::nothrow) ElfSegment( - programHeader->p_offset, programHeader->p_filesz, - programHeader->p_vaddr, programHeader->p_memsz, - (programHeader->p_flags & PF_WRITE) != 0); - if (segment == NULL) - return B_NO_MEMORY; - fSegments.Add(segment); - } - - return B_OK; + if(elfIdent[EI_CLASS] == ELFCLASS64) + return _LoadFile(fileName); + else + return _LoadFile(fileName); } @@ -330,6 +214,134 @@ ElfFile::DataSegment() const } +template +status_t +ElfFile::_LoadFile(const char* fileName) +{ + Ehdr elfHeader; + + // read the elf header + ssize_t bytesRead = pread(fFD, &elfHeader, sizeof(Ehdr), 0); + if (bytesRead != (ssize_t)sizeof(Ehdr)) + return bytesRead < 0 ? errno : B_ERROR; + + // check the ELF header + if (!_CheckRange(0, sizeof(Ehdr)) || !_CheckElfHeader(elfHeader)) { + WARNING("\"%s\": Not an ELF file\n", fileName); + return B_BAD_DATA; + } + + // check section header table values + off_t sectionHeadersOffset = elfHeader.e_shoff; + size_t sectionHeaderSize = elfHeader.e_shentsize; + int sectionCount = elfHeader.e_shnum; + size_t sectionHeaderTableSize = sectionHeaderSize * sectionCount; + if (!_CheckRange(sectionHeadersOffset, sectionHeaderTableSize)) { + WARNING("\"%s\": Invalid ELF header\n", fileName); + return B_BAD_DATA; + } + + // read the section header table + uint8* sectionHeaderTable = (uint8*)malloc(sectionHeaderTableSize); + if (sectionHeaderTable == NULL) + return B_NO_MEMORY; + MemoryDeleter sectionHeaderTableDeleter(sectionHeaderTable); + + bytesRead = pread(fFD, sectionHeaderTable, sectionHeaderTableSize, + sectionHeadersOffset); + if (bytesRead != (ssize_t)sectionHeaderTableSize) + return bytesRead < 0 ? errno : B_ERROR; + + // check and get the section header string section + Shdr* stringSectionHeader = (Shdr*)(sectionHeaderTable + + elfHeader.e_shstrndx * sectionHeaderSize); + if (!_CheckRange(stringSectionHeader->sh_offset, + stringSectionHeader->sh_size)) { + WARNING("\"%s\": Invalid string section header\n", fileName); + return B_BAD_DATA; + } + size_t sectionStringSize = stringSectionHeader->sh_size; + + ElfSection* sectionStringSection = new(std::nothrow) ElfSection(".shstrtab", + fFD, stringSectionHeader->sh_offset, sectionStringSize, + stringSectionHeader->sh_addr, stringSectionHeader->sh_flags); + if (sectionStringSection == NULL) + return B_NO_MEMORY; + fSections.Add(sectionStringSection); + + status_t error = sectionStringSection->Load(); + if (error != B_OK) + return error; + + const char* sectionStrings = (const char*)sectionStringSection->Data(); + + // read the other sections + for (int i = 0; i < sectionCount; i++) { + Shdr* sectionHeader = (Shdr*)(sectionHeaderTable + i + * sectionHeaderSize); + // skip invalid sections and the section header string section + const char* name = sectionStrings + sectionHeader->sh_name; + if (sectionHeader->sh_name >= sectionStringSize + || !_CheckRange(sectionHeader->sh_offset, sectionHeader->sh_size) + || i == elfHeader.e_shstrndx) { + continue; + } + + // create an ElfSection + ElfSection* section = new(std::nothrow) ElfSection(name, fFD, + sectionHeader->sh_offset, sectionHeader->sh_size, + sectionHeader->sh_addr, sectionHeader->sh_flags); + if (section == NULL) + return B_NO_MEMORY; + fSections.Add(section); + } + + // check program header table values + off_t programHeadersOffset = elfHeader.e_phoff; + size_t programHeaderSize = elfHeader.e_phentsize; + int segmentCount = elfHeader.e_phnum; + size_t programHeaderTableSize = programHeaderSize * segmentCount; + if (!_CheckRange(programHeadersOffset, programHeaderTableSize)) { + WARNING("\"%s\": Invalid ELF header\n", fileName); + return B_BAD_DATA; + } + + // read the program header table + uint8* programHeaderTable = (uint8*)malloc(programHeaderTableSize); + if (programHeaderTable == NULL) + return B_NO_MEMORY; + MemoryDeleter programHeaderTableDeleter(programHeaderTable); + + bytesRead = pread(fFD, programHeaderTable, programHeaderTableSize, + programHeadersOffset); + if (bytesRead != (ssize_t)programHeaderTableSize) + return bytesRead < 0 ? errno : B_ERROR; + + // read the program headers and create ElfSegment objects + for (int i = 0; i < segmentCount; i++) { + Phdr* programHeader = (Phdr*)(programHeaderTable + i + * programHeaderSize); + // skip program headers we aren't interested in or that are invalid + if (programHeader->p_type != PT_LOAD || programHeader->p_filesz == 0 + || programHeader->p_memsz == 0 + || !_CheckRange(programHeader->p_offset, programHeader->p_filesz)) { + continue; + } + + // create an ElfSegment + ElfSegment* segment = new(std::nothrow) ElfSegment( + programHeader->p_offset, programHeader->p_filesz, + programHeader->p_vaddr, programHeader->p_memsz, + (programHeader->p_flags & PF_WRITE) != 0); + if (segment == NULL) + return B_NO_MEMORY; + fSegments.Add(segment); + } + + return B_OK; +} + + bool ElfFile::_CheckRange(off_t offset, off_t size) const { @@ -338,16 +350,32 @@ ElfFile::_CheckRange(off_t offset, off_t size) const bool -ElfFile::_CheckElfHeader() const +ElfFile::_CheckElfHeader(Elf32_Ehdr& elfHeader) { - return memcmp(fElfHeader->e_ident, ELF_MAGIC, 4) == 0 - && fElfHeader->e_ident[4] == ELFCLASS32 - && fElfHeader->e_shoff > 0 - && fElfHeader->e_shnum > 0 - && fElfHeader->e_shentsize >= sizeof(struct Elf32_Shdr) - && fElfHeader->e_shstrndx != SHN_UNDEF - && fElfHeader->e_shstrndx < fElfHeader->e_shnum - && fElfHeader->e_phoff > 0 - && fElfHeader->e_phnum > 0 - && fElfHeader->e_phentsize >= sizeof(struct Elf32_Phdr); + return memcmp(elfHeader.e_ident, ELF_MAGIC, 4) == 0 + && elfHeader.e_ident[4] == ELFCLASS32 + && elfHeader.e_shoff > 0 + && elfHeader.e_shnum > 0 + && elfHeader.e_shentsize >= sizeof(struct Elf32_Shdr) + && elfHeader.e_shstrndx != SHN_UNDEF + && elfHeader.e_shstrndx < elfHeader.e_shnum + && elfHeader.e_phoff > 0 + && elfHeader.e_phnum > 0 + && elfHeader.e_phentsize >= sizeof(struct Elf32_Phdr); +} + + +bool +ElfFile::_CheckElfHeader(Elf64_Ehdr& elfHeader) +{ + return memcmp(elfHeader.e_ident, ELF_MAGIC, 4) == 0 + && elfHeader.e_ident[4] == ELFCLASS64 + && elfHeader.e_shoff > 0 + && elfHeader.e_shnum > 0 + && elfHeader.e_shentsize >= sizeof(struct Elf64_Shdr) + && elfHeader.e_shstrndx != SHN_UNDEF + && elfHeader.e_shstrndx < elfHeader.e_shnum + && elfHeader.e_phoff > 0 + && elfHeader.e_phnum > 0 + && elfHeader.e_phentsize >= sizeof(struct Elf64_Phdr); } diff --git a/src/apps/debugger/elf/ElfFile.h b/src/apps/debugger/elf/ElfFile.h index c4e7665aa6..b5069437c4 100644 --- a/src/apps/debugger/elf/ElfFile.h +++ b/src/apps/debugger/elf/ElfFile.h @@ -10,6 +10,7 @@ #include #include +#include #include #include "Types.h" @@ -90,13 +91,16 @@ private: typedef DoublyLinkedList SegmentList; private: + template + status_t _LoadFile(const char* fileName); + bool _CheckRange(off_t offset, off_t size) const; - bool _CheckElfHeader() const; + static bool _CheckElfHeader(Elf32_Ehdr& elfHeader); + static bool _CheckElfHeader(Elf64_Ehdr& elfHeader); private: off_t fFileSize; int fFD; - Elf32_Ehdr* fElfHeader; SectionList fSections; SegmentList fSegments; };