diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/Jamfile b/src/add-ons/kernel/drivers/graphics/intel_extreme/Jamfile index 54e1a5e9f0..27611643cc 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/Jamfile @@ -11,9 +11,9 @@ KernelAddon intel_extreme : driver.cpp device.cpp intel_extreme.cpp + power.cpp kernel_cpp.cpp - : libgraphicscommon.a ; diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp index 462976a998..a6a8c81178 100644 --- a/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/intel_extreme.cpp @@ -10,16 +10,16 @@ #include "intel_extreme.h" #include "AreaKeeper.h" -#include "driver.h" -#include "utility.h" - #include #include #include #include - #include #include +#include "utility.h" + +#include "driver.h" +#include "power.h" #define TRACE_INTELEXTREME @@ -296,38 +296,11 @@ intel_extreme_init(intel_info &info) primary.offset = (addr_t)primary.base - info.aperture_base; } - // Clock gating - // Fix some problems on certain chips (taken from X driver) - // TODO: clean this up - if (info.pci->device_id == 0x2a02 || info.pci->device_id == 0x2a12) { - TRACE("i965GM/i965GME quirk\n"); - write32(info, 0x6204, (1L << 29)); - } else if (info.device_type.InGroup(INTEL_TYPE_SNB)) { - TRACE("SandyBridge clock gating\n"); - write32(info, 0x42020, (1L << 28) | (1L << 7) | (1L << 5)); - } else if (info.device_type.InGroup(INTEL_TYPE_IVB)) { - TRACE("IvyBridge clock gating\n"); - write32(info, 0x42020, (1L << 28)); - } else if (info.device_type.InGroup(INTEL_TYPE_ILK)) { - TRACE("IronLake clock gating\n"); - write32(info, 0x42020, (1L << 7) | (1L << 5)); - } else if (info.device_type.InGroup(INTEL_TYPE_G4x)) { - TRACE("G4x clock gating\n"); - write32(info, 0x6204, 0); - write32(info, 0x6208, (1L << 9) | (1L << 7) | (1L << 6)); - write32(info, 0x6210, 0); + // Enable clock gating + intel_en_gating(info); - uint32 gateValue = (1L << 28) | (1L << 3) | (1L << 2); - if ((info.device_type.type & INTEL_TYPE_MOBILE) == INTEL_TYPE_MOBILE) { - TRACE("G4x mobile clock gating\n"); - gateValue |= 1L << 18; - } - write32(info, 0x6200, gateValue); - } else { - TRACE("i965 quirk\n"); - write32(info, 0x6204, (1L << 29) | (1L << 23)); - } - write32(info, 0x7408, 0x10); + // Enable automatic gpu downclocking if we can to save power + intel_en_downclock(info); // no errors, so keep areas and mappings sharedCreator.Detach(); diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/power.cpp b/src/add-ons/kernel/drivers/graphics/intel_extreme/power.cpp new file mode 100644 index 0000000000..9c4f6c7e8b --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/power.cpp @@ -0,0 +1,175 @@ +/* + * Copyright 2012-2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Alexander von Gluck IV, kallisti5@unixzen.com + */ + + +#include "power.h" + + +#undef TRACE +#define TRACE_POWER +#ifdef TRACE_POWER +# define TRACE(x...) dprintf("intel_extreme:" x) +#else +# define TRACE(x...) +#endif + +#define ERROR(x...) dprintf("intel_extreme: " x) +#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) + + +status_t +intel_en_gating(intel_info &info) +{ + CALLED(); + // Fix some problems on certain chips (taken from X driver) + // TODO: clean this up + if (info.pci->device_id == 0x2a02 || info.pci->device_id == 0x2a12) { + TRACE("i965GM/i965GME quirk\n"); + write32(info, 0x6204, (1L << 29)); + } else if (info.device_type.InGroup(INTEL_TYPE_SNB)) { + TRACE("SandyBridge clock gating\n"); + write32(info, 0x42020, (1L << 28) | (1L << 7) | (1L << 5)); + } else if (info.device_type.InGroup(INTEL_TYPE_IVB)) { + TRACE("IvyBridge clock gating\n"); + write32(info, 0x42020, (1L << 28)); + } else if (info.device_type.InGroup(INTEL_TYPE_ILK)) { + TRACE("IronLake clock gating\n"); + write32(info, 0x42020, (1L << 7) | (1L << 5)); + } else if (info.device_type.InGroup(INTEL_TYPE_G4x)) { + TRACE("G4x clock gating\n"); + write32(info, 0x6204, 0); + write32(info, 0x6208, (1L << 9) | (1L << 7) | (1L << 6)); + write32(info, 0x6210, 0); + + uint32 gateValue = (1L << 28) | (1L << 3) | (1L << 2); + if ((info.device_type.type & INTEL_TYPE_MOBILE) == INTEL_TYPE_MOBILE) { + TRACE("G4x mobile clock gating\n"); + gateValue |= 1L << 18; + } + write32(info, 0x6200, gateValue); + } else { + TRACE("i965 quirk\n"); + write32(info, 0x6204, (1L << 29) | (1L << 23)); + } + write32(info, 0x7408, 0x10); + + return B_OK; +} + + +status_t +intel_en_downclock(intel_info &info) +{ + CALLED(); + + if (!info.device_type.InGroup(INTEL_TYPE_SNB) + && !info.device_type.InGroup(INTEL_TYPE_IVB)) { + TRACE("%s: Downclocking not supported on this chipset.\n", __func__); + return B_NOT_ALLOWED; + } + + if((info.device_type.type & INTEL_TYPE_MOBILE) == 0) { + // I don't see a point enabling auto-downclocking on non-mobile devices. + TRACE("%s: Skip GPU downclocking on non-mobile device.\n", __func__); + return B_NOT_ALLOWED; + } + // TODO: Check for deep RC6 + // IvyBridge, SandyBridge, and Haswell can do depth 1 atm + // Some chipsets can go deeper... but this is safe for now + // Haswell should *NOT* do over depth 1; + int depth = 1; + + // Lets always print this for now incase it causes regressions for someone. + ERROR("%s: Enabling Intel GPU auto downclocking depth %d\n", __func__, + depth); + + /* Magical sequence of register writes to enable + * downclocking from the fine folks at Xorg + */ + write32(info, INTEL6_RC_STATE, 0); + + uint32 rpStateCapacity = read32(info, INTEL6_RP_STATE_CAP); + uint32 gtPerfStatus = read32(info, INTEL6_GT_PERF_STATUS); + uint8 maxDelay = rpStateCapacity & 0xff; + uint8 minDelay = (rpStateCapacity & 0xff0000) >> 16; + + write32(info, INTEL6_RC_CONTROL, 0); + + write32(info, INTEL6_RC1_WAKE_RATE_LIMIT, 1000 << 16); + write32(info, INTEL6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30); + write32(info, INTEL6_RC6pp_WAKE_RATE_LIMIT, 30); + write32(info, INTEL6_RC_EVALUATION_INTERVAL, 125000); + write32(info, INTEL6_RC_IDLE_HYSTERSIS, 25); + + // TODO: Idle each ring + + write32(info, INTEL6_RC_SLEEP, 0); + write32(info, INTEL6_RC1e_THRESHOLD, 1000); + write32(info, INTEL6_RC6_THRESHOLD, 50000); + write32(info, INTEL6_RC6p_THRESHOLD, 100000); + write32(info, INTEL6_RC6pp_THRESHOLD, 64000); + + uint32 rc6Mask = INTEL6_RC_CTL_RC6_ENABLE; + + if (depth > 1) + rc6Mask |= INTEL6_RC_CTL_RC6p_ENABLE; + if (depth > 2) + rc6Mask |= INTEL6_RC_CTL_RC6pp_ENABLE; + + write32(info, INTEL6_RC_CONTROL, rc6Mask | INTEL6_RC_CTL_EI_MODE(1) + | INTEL6_RC_CTL_HW_ENABLE); + write32(info, INTEL6_RPNSWREQ, INTEL6_FREQUENCY(10) | INTEL6_OFFSET(0) + | INTEL6_AGGRESSIVE_TURBO); + write32(info, INTEL6_RC_VIDEO_FREQ, INTEL6_FREQUENCY(12)); + + write32(info, INTEL6_RP_DOWN_TIMEOUT, 1000000); + write32(info, INTEL6_RP_INTERRUPT_LIMITS, maxDelay << 24 | minDelay << 16); + + write32(info, INTEL6_RP_UP_THRESHOLD, 59400); + write32(info, INTEL6_RP_DOWN_THRESHOLD, 245000); + write32(info, INTEL6_RP_UP_EI, 66000); + write32(info, INTEL6_RP_DOWN_EI, 350000); + + write32(info, INTEL6_RP_IDLE_HYSTERSIS, 10); + write32(info, INTEL6_RP_CONTROL, INTEL6_RP_MEDIA_TURBO + | INTEL6_RP_MEDIA_HW_NORMAL_MODE | INTEL6_RP_MEDIA_IS_GFX + | INTEL6_RP_ENABLE | INTEL6_RP_UP_BUSY_AVG + | INTEL6_RP_DOWN_IDLE_CONT); + // TODO: | (HASWELL ? GEN7_RP_DOWN_IDLE_AVG : INTEL6_RP_DOWN_IDLE_CONT)); + + // TODO: wait for (read32(INTEL6_PCODE_MAILBOX) & INTEL6_PCODE_READY) + write32(info, INTEL6_PCODE_DATA, 0); + write32(info, INTEL6_PCODE_MAILBOX, INTEL6_PCODE_READY + | INTEL6_PCODE_WRITE_MIN_FREQ_TABLE); + // TODO: wait for (read32(INTEL6_PCODE_MAILBOX) & INTEL6_PCODE_READY) + + // TODO: check for overclock support and set. + + // Calculate limits and enforce them + uint8 gtPerfShift = (gtPerfStatus & 0xff00) >> 8; + if (gtPerfShift >= maxDelay) + gtPerfShift = maxDelay; + uint32 limits = maxDelay << 24; + if (gtPerfShift <= minDelay) { + gtPerfShift = minDelay; + limits |= minDelay << 16; + } + write32(info, INTEL6_RP_INTERRUPT_LIMITS, limits); + + write32(info, INTEL6_RPNSWREQ, INTEL6_FREQUENCY(gtPerfShift) + | INTEL6_OFFSET(0) | INTEL6_AGGRESSIVE_TURBO); + + // Requires MSI to be enabled. + write32(info, INTEL6_PMIER, INTEL6_PM_DEFERRED_EVENTS); + // TODO: Review need for spin lock irq rps here? + write32(info, INTEL6_PMIMR, 0); + // TODO: Review need for spin unlock irq rps here? + write32(info, INTEL6_PMINTRMSK, 0); + + return B_OK; +} \ No newline at end of file diff --git a/src/add-ons/kernel/drivers/graphics/intel_extreme/power.h b/src/add-ons/kernel/drivers/graphics/intel_extreme/power.h new file mode 100644 index 0000000000..c75acef70d --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/intel_extreme/power.h @@ -0,0 +1,121 @@ +/* + * Copyright 2012-2013, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Alexander von Gluck IV, kallisti5@unixzen.com + */ +#ifndef _INTEL_POWER_H_ +#define _INTEL_POWER_H_ + + +#include + +#include "driver.h" + + +// Clocking configuration +#define INTEL6_GT_THREAD_STATUS_REG 0x13805c +#define INTEL6_GT_THREAD_STATUS_CORE_MASK 0x7 +#define INTEL6_GT_THREAD_STATUS_CORE_MASK_HSW (0x7 | (0x07 << 16)) +#define INTEL6_GT_PERF_STATUS 0x145948 +#define INTEL6_RP_STATE_LIMITS 0x145994 +#define INTEL6_RP_STATE_CAP 0x145998 +#define INTEL6_RPNSWREQ 0xA008 +#define INTEL6_TURBO_DISABLE (1<<31) +#define INTEL6_FREQUENCY(x) ((x)<<25) +#define INTEL6_OFFSET(x) ((x)<<19) +#define INTEL6_AGGRESSIVE_TURBO (0<<15) +#define INTEL6_RC_VIDEO_FREQ 0xA00C +#define INTEL6_RC_CONTROL 0xA090 +#define INTEL6_RC_CTL_RC6pp_ENABLE (1<<16) +#define INTEL6_RC_CTL_RC6p_ENABLE (1<<17) +#define INTEL6_RC_CTL_RC6_ENABLE (1<<18) +#define INTEL6_RC_CTL_RC1e_ENABLE (1<<20) +#define INTEL6_RC_CTL_RC7_ENABLE (1<<22) +#define INTEL6_RC_CTL_EI_MODE(x) ((x)<<27) +#define INTEL6_RC_CTL_HW_ENABLE (1<<31) +#define INTEL6_RP_DOWN_TIMEOUT 0xA010 +#define INTEL6_RP_INTERRUPT_LIMITS 0xA014 +#define INTEL6_RPSTAT1 0xA01C +#define INTEL6_CAGF_SHIFT 8 +#define INTEL6_CAGF_MASK (0x7f << INTEL6_CAGF_SHIFT) +#define INTEL6_RP_CONTROL 0xA024 +#define INTEL6_RP_MEDIA_TURBO (1<<11) +#define INTEL6_RP_MEDIA_MODE_MASK (3<<9) +#define INTEL6_RP_MEDIA_HW_TURBO_MODE (3<<9) +#define INTEL6_RP_MEDIA_HW_NORMAL_MODE (2<<9) +#define INTEL6_RP_MEDIA_HW_MODE (1<<9) +#define INTEL6_RP_MEDIA_SW_MODE (0<<9) +#define INTEL6_RP_MEDIA_IS_GFX (1<<8) +#define INTEL6_RP_ENABLE (1<<7) +#define INTEL6_RP_UP_IDLE_MIN (0x1<<3) +#define INTEL6_RP_UP_BUSY_AVG (0x2<<3) +#define INTEL6_RP_UP_BUSY_CONT (0x4<<3) +#define GEN7_RP_DOWN_IDLE_AVG (0x2<<0) +#define INTEL6_RP_DOWN_IDLE_CONT (0x1<<0) +#define INTEL6_RP_UP_THRESHOLD 0xA02C +#define INTEL6_RP_DOWN_THRESHOLD 0xA030 +#define INTEL6_RP_CUR_UP_EI 0xA050 +#define INTEL6_CURICONT_MASK 0xffffff +#define INTEL6_RP_CUR_UP 0xA054 +#define INTEL6_CURBSYTAVG_MASK 0xffffff +#define INTEL6_RP_PREV_UP 0xA058 +#define INTEL6_RP_CUR_DOWN_EI 0xA05C +#define INTEL6_CURIAVG_MASK 0xffffff +#define INTEL6_RP_CUR_DOWN 0xA060 +#define INTEL6_RP_PREV_DOWN 0xA064 +#define INTEL6_RP_UP_EI 0xA068 +#define INTEL6_RP_DOWN_EI 0xA06C +#define INTEL6_RP_IDLE_HYSTERSIS 0xA070 +#define INTEL6_RC_STATE 0xA094 +#define INTEL6_RC1_WAKE_RATE_LIMIT 0xA098 +#define INTEL6_RC6_WAKE_RATE_LIMIT 0xA09C +#define INTEL6_RC6pp_WAKE_RATE_LIMIT 0xA0A0 +#define INTEL6_RC_EVALUATION_INTERVAL 0xA0A8 +#define INTEL6_RC_IDLE_HYSTERSIS 0xA0AC +#define INTEL6_RC_SLEEP 0xA0B0 +#define INTEL6_RC1e_THRESHOLD 0xA0B4 +#define INTEL6_RC6_THRESHOLD 0xA0B8 +#define INTEL6_RC6p_THRESHOLD 0xA0BC +#define INTEL6_RC6pp_THRESHOLD 0xA0C0 +#define INTEL6_PMINTRMSK 0xA168 +#define INTEL6_PMISR 0x44020 +#define INTEL6_PMIMR 0x44024 /* rps_lock */ +#define INTEL6_PMIIR 0x44028 +#define INTEL6_PMIER 0x4402C +#define INTEL6_PM_MBOX_EVENT (1<<25) +#define INTEL6_PM_THERMAL_EVENT (1<<24) +#define INTEL6_PM_RP_DOWN_TIMEOUT (1<<6) +#define INTEL6_PM_RP_UP_THRESHOLD (1<<5) +#define INTEL6_PM_RP_DOWN_THRESHOLD (1<<4) +#define INTEL6_PM_RP_UP_EI_EXPIRED (1<<2) +#define INTEL6_PM_RP_DOWN_EI_EXPIRED (1<<1) +#define INTEL6_PM_DEFERRED_EVENTS (INTEL6_PM_RP_UP_THRESHOLD \ + | INTEL6_PM_RP_DOWN_THRESHOLD \ + | INTEL6_PM_RP_DOWN_TIMEOUT) +#define INTEL6_GT_GFX_RC6_LOCKED 0x138104 +#define INTEL6_GT_GFX_RC6 0x138108 +#define INTEL6_GT_GFX_RC6p 0x13810C +#define INTEL6_GT_GFX_RC6pp 0x138110 +#define INTEL6_PCODE_MAILBOX 0x138124 +#define INTEL6_PCODE_READY (1<<31) +#define INTEL6_READ_OC_PARAMS 0xc +#define INTEL6_PCODE_WRITE_MIN_FREQ_TABLE 0x8 +#define INTEL6_PCODE_READ_MIN_FREQ_TABLE 0x9 +#define INTEL6_PCODE_DATA 0x138128 +#define INTEL6_PCODE_FREQ_IA_RATIO_SHIFT 8 +#define INTEL6_GT_CORE_STATUS 0x138060 +#define INTEL6_CORE_CPD_STATE_MASK (7<<4) +#define INTEL6_RCn_MASK 7 +#define INTEL6_RC0 0 +#define INTEL6_RC3 2 +#define INTEL6_RC6 3 +#define INTEL6_RC7 4 + + +status_t intel_en_gating(intel_info &info); +status_t intel_en_downclock(intel_info &info); + + +#endif /* _INTEL_POWER_H_ */ \ No newline at end of file diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 44c56d0a89..c2aaa66bd9 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -124,9 +124,10 @@ Application Debugger : # ids FunctionID.cpp + FunctionParameterID.cpp LocalVariableID.cpp ObjectID.cpp - FunctionParameterID.cpp + ReturnValueID.cpp # jobs GetCPUStateJob.cpp diff --git a/src/apps/debugger/arch/Architecture.cpp b/src/apps/debugger/arch/Architecture.cpp index 01b39992e5..c1724f78ec 100644 --- a/src/apps/debugger/arch/Architecture.cpp +++ b/src/apps/debugger/arch/Architecture.cpp @@ -94,8 +94,8 @@ Architecture::InitRegisterRules(CfaContext& context) const status_t Architecture::CreateStackTrace(Team* team, ImageDebugInfoProvider* imageInfoProvider, CpuState* cpuState, - StackTrace*& _stackTrace, int32 maxStackDepth, bool useExistingTrace, - bool getFullFrameInfo) + StackTrace*& _stackTrace, target_addr_t returnFunctionAddress, + int32 maxStackDepth, bool useExistingTrace, bool getFullFrameInfo) { BReference cpuStateReference(cpuState); @@ -163,7 +163,8 @@ Architecture::CreateStackTrace(Team* team, if (function != NULL) { status_t error = functionDebugInfo->GetSpecificImageDebugInfo() ->CreateFrame(image, function, cpuState, getFullFrameInfo, - frame, previousCpuState); + nextFrame == NULL ? returnFunctionAddress : 0, frame, + previousCpuState); if (error != B_OK && error != B_UNSUPPORTED) break; } diff --git a/src/apps/debugger/arch/Architecture.h b/src/apps/debugger/arch/Architecture.h index 38409d0a3a..d9610ba77f 100644 --- a/src/apps/debugger/arch/Architecture.h +++ b/src/apps/debugger/arch/Architecture.h @@ -30,6 +30,7 @@ class StackTrace; class Statement; class Team; class TeamMemory; +class ValueLocation; enum { @@ -102,12 +103,14 @@ public: target_addr_t address, Statement*& _statement) = 0; virtual status_t GetInstructionInfo(target_addr_t address, - InstructionInfo& _info) = 0; + InstructionInfo& _info, + CpuState* state) = 0; status_t CreateStackTrace(Team* team, ImageDebugInfoProvider* imageInfoProvider, CpuState* cpuState, StackTrace*& _stackTrace, + target_addr_t returnFunctionAddress, int32 maxStackDepth = -1, bool useExistingTrace = false, bool getFullFrameInfo = true); @@ -118,6 +121,10 @@ public: int32& _maxBytesPerRegister, uint8& _watchpointCapabilityFlags) = 0; + virtual status_t GetReturnAddressLocation( + StackFrame* frame, target_size_t valueSize, + ValueLocation*& _location) = 0; + protected: TeamMemory* fTeamMemory; diff --git a/src/apps/debugger/arch/InstructionInfo.cpp b/src/apps/debugger/arch/InstructionInfo.cpp index 03afae474e..1a48c70848 100644 --- a/src/apps/debugger/arch/InstructionInfo.cpp +++ b/src/apps/debugger/arch/InstructionInfo.cpp @@ -9,6 +9,7 @@ InstructionInfo::InstructionInfo() : fAddress(0), + fTargetAddress(0), fSize(0), fType(INSTRUCTION_TYPE_OTHER), fBreakpointAllowed(false), @@ -17,11 +18,13 @@ InstructionInfo::InstructionInfo() } -InstructionInfo::InstructionInfo(target_addr_t address, target_size_t size, +InstructionInfo::InstructionInfo(target_addr_t address, + target_addr_t targetAddress, target_size_t size, instruction_type type, bool breakpointAllowed, const BString& disassembledLine) : fAddress(address), + fTargetAddress(targetAddress), fSize(size), fType(type), fBreakpointAllowed(breakpointAllowed), @@ -31,11 +34,12 @@ InstructionInfo::InstructionInfo(target_addr_t address, target_size_t size, bool -InstructionInfo::SetTo(target_addr_t address, target_size_t size, - instruction_type type, bool breakpointAllowed, +InstructionInfo::SetTo(target_addr_t address, target_addr_t targetAddress, + target_size_t size, instruction_type type, bool breakpointAllowed, const BString& disassembledLine) { fAddress = address; + fTargetAddress = targetAddress; fSize = size; fType = type; fBreakpointAllowed = breakpointAllowed; diff --git a/src/apps/debugger/arch/InstructionInfo.h b/src/apps/debugger/arch/InstructionInfo.h index 36c2fa2834..25e9e365cd 100644 --- a/src/apps/debugger/arch/InstructionInfo.h +++ b/src/apps/debugger/arch/InstructionInfo.h @@ -12,6 +12,7 @@ enum instruction_type { INSTRUCTION_TYPE_SUBROUTINE_CALL, + INSTRUCTION_TYPE_JUMP, INSTRUCTION_TYPE_OTHER }; @@ -20,16 +21,21 @@ class InstructionInfo { public: InstructionInfo(); InstructionInfo(target_addr_t address, + target_addr_t targetAddress, target_size_t size, instruction_type type, bool breakpointAllowed, const BString& disassembledLine); - bool SetTo(target_addr_t address, target_size_t size, + bool SetTo(target_addr_t address, + target_addr_t targetAddress, + target_size_t size, instruction_type type, bool breakpointAllowed, const BString& disassembledLine); target_addr_t Address() const { return fAddress; } + target_addr_t TargetAddress() const + { return fTargetAddress; } target_size_t Size() const { return fSize; } instruction_type Type() const { return fType; } bool IsBreakpointAllowed() const @@ -40,6 +46,7 @@ public: private: target_addr_t fAddress; + target_addr_t fTargetAddress; target_size_t fSize; instruction_type fType; bool fBreakpointAllowed; diff --git a/src/apps/debugger/arch/x86/ArchitectureX86.cpp b/src/apps/debugger/arch/x86/ArchitectureX86.cpp index dd19a9012d..39e5c7f71b 100644 --- a/src/apps/debugger/arch/x86/ArchitectureX86.cpp +++ b/src/apps/debugger/arch/x86/ArchitectureX86.cpp @@ -23,6 +23,7 @@ #include "StackFrame.h" #include "Statement.h" #include "TeamMemory.h" +#include "ValueLocation.h" #include "X86AssemblyLanguage.h" #include "disasm/DisassemblerX86.h" @@ -560,7 +561,7 @@ ArchitectureX86::GetStatement(FunctionDebugInfo* function, // TODO: This is not architecture dependent anymore! // get the instruction info InstructionInfo info; - status_t error = GetInstructionInfo(address, info); + status_t error = GetInstructionInfo(address, info, NULL); if (error != B_OK) return error; @@ -577,11 +578,10 @@ ArchitectureX86::GetStatement(FunctionDebugInfo* function, status_t ArchitectureX86::GetInstructionInfo(target_addr_t address, - InstructionInfo& _info) + InstructionInfo& _info, CpuState* state) { - // read the code + // read the code - maximum x86{-64} instruction size = 15 bytes uint8 buffer[16]; - // TODO: What's the maximum instruction size? ssize_t bytesRead = fTeamMemory->ReadMemory(address, buffer, sizeof(buffer)); if (bytesRead < 0) @@ -593,35 +593,7 @@ ArchitectureX86::GetInstructionInfo(target_addr_t address, 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; - - 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; + return disassembler.GetNextInstructionInfo(_info, state); } @@ -643,6 +615,52 @@ ArchitectureX86::GetWatchpointDebugCapabilities(int32& _maxRegisterCount, } +status_t +ArchitectureX86::GetReturnAddressLocation(StackFrame* frame, + target_size_t valueSize, ValueLocation*& _location) +{ + // for the calling conventions currently in use on Haiku, + // the x86 rules for how values are returned are as follows: + // + // - 32 bits or smaller values are returned directly in EAX. + // - 32-64 bit values are returned across EAX:EDX. + // - > 64 bit values are returned on the stack. + ValueLocation* location = new(std::nothrow) ValueLocation( + IsBigEndian()); + if (location == NULL) + return B_NO_MEMORY; + BReference locationReference(location, + true); + + if (valueSize <= 4) { + ValuePieceLocation piece; + piece.SetSize(valueSize); + piece.SetToRegister(X86_REGISTER_EAX); + if (!location->AddPiece(piece)) + return B_NO_MEMORY; + } else if (valueSize <= 8) { + ValuePieceLocation piece; + piece.SetSize(4); + piece.SetToRegister(X86_REGISTER_EAX); + if (!location->AddPiece(piece)) + return B_NO_MEMORY; + piece.SetToRegister(X86_REGISTER_EDX); + piece.SetSize(valueSize - 4); + if (!location->AddPiece(piece)) + return B_NO_MEMORY; + } else { + ValuePieceLocation piece; + piece.SetToMemory(frame->GetCpuState()->StackPointer()); + piece.SetSize(valueSize); + if (!location->AddPiece(piece)) + return B_NO_MEMORY; + } + + _location = locationReference.Detach(); + return B_OK; +} + + void ArchitectureX86::_AddRegister(int32 index, const char* name, uint32 bitSize, uint32 valueType, register_type type, bool calleePreserved) diff --git a/src/apps/debugger/arch/x86/ArchitectureX86.h b/src/apps/debugger/arch/x86/ArchitectureX86.h index 48e849c502..1a6120cfa2 100644 --- a/src/apps/debugger/arch/x86/ArchitectureX86.h +++ b/src/apps/debugger/arch/x86/ArchitectureX86.h @@ -59,13 +59,18 @@ public: target_addr_t address, Statement*& _statement); virtual status_t GetInstructionInfo(target_addr_t address, - InstructionInfo& _info); + InstructionInfo& _info, CpuState* state); virtual status_t GetWatchpointDebugCapabilities( int32& _maxRegisterCount, int32& _maxBytesPerRegister, uint8& _watchpointCapabilityFlags); + virtual status_t GetReturnAddressLocation( + StackFrame* frame, target_size_t valueSize, + ValueLocation*& _location); + + private: struct ToDwarfRegisterMap; struct FromDwarfRegisterMap; diff --git a/src/apps/debugger/arch/x86/disasm/DisassemblerX86.cpp b/src/apps/debugger/arch/x86/disasm/DisassemblerX86.cpp index f20838e31e..e686d7e7f8 100644 --- a/src/apps/debugger/arch/x86/disasm/DisassemblerX86.cpp +++ b/src/apps/debugger/arch/x86/disasm/DisassemblerX86.cpp @@ -12,6 +12,36 @@ #include +#include "CpuStateX86.h" +#include "InstructionInfo.h" + + +static uint8 RegisterNumberFromUdisIndex(int32 udisIndex) +{ + switch (udisIndex) { + case UD_R_RIP: return X86_REGISTER_EIP; + case UD_R_ESP: return X86_REGISTER_ESP; + case UD_R_EBP: return X86_REGISTER_EBP; + + case UD_R_EAX: return X86_REGISTER_EAX; + case UD_R_EBX: return X86_REGISTER_EBX; + case UD_R_ECX: return X86_REGISTER_ECX; + case UD_R_EDX: return X86_REGISTER_EDX; + + case UD_R_ESI: return X86_REGISTER_ESI; + case UD_R_EDI: return X86_REGISTER_EDI; + + case UD_R_CS: return X86_REGISTER_CS; + case UD_R_DS: return X86_REGISTER_DS; + case UD_R_ES: return X86_REGISTER_ES; + case UD_R_FS: return X86_REGISTER_FS; + case UD_R_GS: return X86_REGISTER_GS; + case UD_R_SS: return X86_REGISTER_SS; + } + + return X86_INT_REGISTER_END; +} + struct DisassemblerX86::UdisData : ud_t { }; @@ -108,3 +138,85 @@ DisassemblerX86::GetPreviousInstruction(target_addr_t nextAddress, } } } + + +status_t +DisassemblerX86::GetNextInstructionInfo(InstructionInfo& _info, + CpuState* state) +{ + unsigned int size = ud_disassemble(fUdisData); + if (size < 1) + return B_ENTRY_NOT_FOUND; + + uint32 address = (uint32)ud_insn_off(fUdisData); + + instruction_type type = INSTRUCTION_TYPE_OTHER; + target_addr_t targetAddress = 0; + + if (fUdisData->mnemonic == UD_Icall) + type = INSTRUCTION_TYPE_SUBROUTINE_CALL; + else if (fUdisData->mnemonic == UD_Ijmp) + type = INSTRUCTION_TYPE_JUMP; + if (state != NULL) + targetAddress = GetInstructionTargetAddress(state); + + char buffer[256]; + snprintf(buffer, sizeof(buffer), "0x%08" B_PRIx32 ": %16.16s %s", address, + ud_insn_hex(fUdisData), ud_insn_asm(fUdisData)); + // TODO: Resolve symbols! + + if (!_info.SetTo(address, targetAddress, size, type, true, buffer)) + return B_NO_MEMORY; + + return B_OK; +} + + +target_addr_t +DisassemblerX86::GetInstructionTargetAddress(CpuState* state) const +{ + if (fUdisData->mnemonic != UD_Icall && fUdisData->mnemonic != UD_Ijmp) + return 0; + + CpuStateX86* x86State = dynamic_cast(state); + if (x86State == NULL) + return 0; + + target_addr_t targetAddress = 0; + switch (fUdisData->operand[0].type) { + case UD_OP_REG: + { + targetAddress = x86State->IntRegisterValue( + RegisterNumberFromUdisIndex(fUdisData->operand[0].base)); + targetAddress += fUdisData->operand[0].offset; + } + break; + case UD_OP_MEM: + { + targetAddress = x86State->IntRegisterValue( + RegisterNumberFromUdisIndex(fUdisData->operand[0].base)); + targetAddress += x86State->IntRegisterValue( + RegisterNumberFromUdisIndex(fUdisData->operand[0].index)) + * fUdisData->operand[0].scale; + } + break; + case UD_OP_JIMM: + { + targetAddress = ud_insn_off(fUdisData) + + fUdisData->operand[0].lval.sdword + ud_insn_len(fUdisData); + } + break; + + case UD_OP_IMM: + case UD_OP_CONST: + { + targetAddress = fUdisData->operand[0].lval.udword; + } + break; + + default: + break; + } + + return targetAddress; +} diff --git a/src/apps/debugger/arch/x86/disasm/DisassemblerX86.h b/src/apps/debugger/arch/x86/disasm/DisassemblerX86.h index b66a0adbcd..9d4952560d 100644 --- a/src/apps/debugger/arch/x86/disasm/DisassemblerX86.h +++ b/src/apps/debugger/arch/x86/disasm/DisassemblerX86.h @@ -10,6 +10,10 @@ #include "Types.h" +class CpuState; +class InstructionInfo; + + class DisassemblerX86 { public: DisassemblerX86(); @@ -27,6 +31,14 @@ public: target_addr_t& _address, target_size_t& _size); + virtual status_t GetNextInstructionInfo( + InstructionInfo& _info, + CpuState* state); + + +private: + target_addr_t GetInstructionTargetAddress( + CpuState* state) const; private: struct UdisData; diff --git a/src/apps/debugger/arch/x86/disasm/Jamfile b/src/apps/debugger/arch/x86/disasm/Jamfile index a916ab0144..0b40f9f7e0 100644 --- a/src/apps/debugger/arch/x86/disasm/Jamfile +++ b/src/apps/debugger/arch/x86/disasm/Jamfile @@ -3,9 +3,12 @@ SubDir HAIKU_TOP src apps debugger arch x86 disasm ; CCFLAGS += -Werror ; C++FLAGS += -Werror ; +UsePrivateHeaders shared ; + UseHeaders [ LibraryHeaders udis86 ] ; UseHeaders [ LibraryHeaders [ FDirName udis86 libudis86 ] ] ; +SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ; SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ; SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) $(DOTDOT) types ] ; diff --git a/src/apps/debugger/arch/x86_64/ArchitectureX8664.cpp b/src/apps/debugger/arch/x86_64/ArchitectureX8664.cpp index 21525627e7..05ba2a4315 100644 --- a/src/apps/debugger/arch/x86_64/ArchitectureX8664.cpp +++ b/src/apps/debugger/arch/x86_64/ArchitectureX8664.cpp @@ -451,7 +451,7 @@ ArchitectureX8664::GetStatement(FunctionDebugInfo* function, // TODO: This is not architecture dependent anymore! // get the instruction info InstructionInfo info; - status_t error = GetInstructionInfo(address, info); + status_t error = GetInstructionInfo(address, info, NULL); if (error != B_OK) return error; @@ -468,7 +468,7 @@ ArchitectureX8664::GetStatement(FunctionDebugInfo* function, status_t ArchitectureX8664::GetInstructionInfo(target_addr_t address, - InstructionInfo& _info) + InstructionInfo& _info, CpuState* state) { // read the code uint8 buffer[16]; @@ -487,6 +487,7 @@ ArchitectureX8664::GetInstructionInfo(target_addr_t address, // disassemble the instruction BString line; target_addr_t instructionAddress; + target_addr_t targetAddress = 0; target_size_t instructionSize; bool breakpointAllowed; error = disassembler.GetNextInstruction(line, instructionAddress, @@ -508,8 +509,8 @@ ArchitectureX8664::GetInstructionInfo(target_addr_t address, } } - if (!_info.SetTo(instructionAddress, instructionSize, instructionType, - breakpointAllowed, line)) { + if (!_info.SetTo(instructionAddress, targetAddress, instructionSize, + instructionType, breakpointAllowed, line)) { return B_NO_MEMORY; } @@ -534,6 +535,13 @@ ArchitectureX8664::GetWatchpointDebugCapabilities(int32& _maxRegisterCount, } +status_t +ArchitectureX8664::GetReturnAddressLocation(StackFrame* frame, + target_size_t valueSize, ValueLocation*& _location) { + return B_NOT_SUPPORTED; +} + + void ArchitectureX8664::_AddRegister(int32 index, const char* name, uint32 bitSize, uint32 valueType, register_type type, bool calleePreserved) diff --git a/src/apps/debugger/arch/x86_64/ArchitectureX8664.h b/src/apps/debugger/arch/x86_64/ArchitectureX8664.h index ec814483f0..2ff90bedec 100644 --- a/src/apps/debugger/arch/x86_64/ArchitectureX8664.h +++ b/src/apps/debugger/arch/x86_64/ArchitectureX8664.h @@ -60,13 +60,17 @@ public: target_addr_t address, Statement*& _statement); virtual status_t GetInstructionInfo(target_addr_t address, - InstructionInfo& _info); + InstructionInfo& _info, CpuState* state); virtual status_t GetWatchpointDebugCapabilities( int32& _maxRegisterCount, int32& _maxBytesPerRegister, uint8& _watchpointCapabilityFlags); + virtual status_t GetReturnAddressLocation( + StackFrame* frame, target_size_t valueSize, + ValueLocation*& _location); + private: struct ToDwarfRegisterMap; struct FromDwarfRegisterMap; diff --git a/src/apps/debugger/controllers/ThreadHandler.cpp b/src/apps/debugger/controllers/ThreadHandler.cpp index f9161060a2..6a2fe948fb 100644 --- a/src/apps/debugger/controllers/ThreadHandler.cpp +++ b/src/apps/debugger/controllers/ThreadHandler.cpp @@ -253,8 +253,8 @@ ThreadHandler::HandleThreadAction(uint32 action) if (stackTrace == NULL && cpuState != NULL) { if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( - fThread->GetTeam(), this, cpuState, stackTrace, 1, false, - false) == B_OK) { + fThread->GetTeam(), this, cpuState, stackTrace, 0, 1, + false, false) == B_OK) { stackTraceReference.SetTo(stackTrace, true); } } @@ -469,7 +469,7 @@ ThreadHandler::_DoStepOver(CpuState* cpuState) // just single-step, otherwise we set a breakpoint after the instruction. InstructionInfo info; if (fDebuggerInterface->GetArchitecture()->GetInstructionInfo( - cpuState->InstructionPointer(), info) != B_OK) { + cpuState->InstructionPointer(), info, cpuState) != B_OK) { TRACE_CONTROL(" failed to get instruction info\n"); return false; } @@ -484,6 +484,7 @@ ThreadHandler::_DoStepOver(CpuState* cpuState) TRACE_CONTROL(" subroutine call -- installing breakpoint at address " "%#" B_PRIx64 "\n", info.Address() + info.Size()); + fThread->SetExecutedSubroutine(info.TargetAddress()); if (_InstallTemporaryBreakpoint(info.Address() + info.Size()) != B_OK) return false; @@ -565,9 +566,8 @@ ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState) if (stackTrace == NULL && cpuState != NULL) { if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( - fThread->GetTeam(), this, cpuState, stackTrace, 1, - false, false) - == B_OK) { + fThread->GetTeam(), this, cpuState, stackTrace, 0, 1, + false, false) == B_OK) { stackTraceReference.SetTo(stackTrace, true); } } @@ -576,7 +576,7 @@ ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState) // If we're not in the same frame we started in, // keep executing. if (frame != NULL && fPreviousFrameAddress - != stackTrace->FrameAt(0)->FrameAddress()) { + != frame->FrameAddress()) { status_t error = _InstallTemporaryBreakpoint( cpuState->InstructionPointer()); if (error != B_OK) @@ -608,6 +608,7 @@ ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState) // That's the return address, so we're done in theory, // unless we're a recursive function. Check if we've actually // exited the previous stack frame or not. + fThread->SetExecutedSubroutine(cpuState->InstructionPointer()); target_addr_t framePointer = cpuState->StackFramePointer(); bool hasExitedFrame = fDebuggerInterface->GetArchitecture() ->StackGrowthDirection() == STACK_GROWTH_DIRECTION_POSITIVE @@ -652,9 +653,8 @@ ThreadHandler::_HandleSingleStepStep(CpuState* cpuState) if (stackTrace == NULL && cpuState != NULL) { if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( - fThread->GetTeam(), this, cpuState, stackTrace, 1, - false, false) - == B_OK) { + fThread->GetTeam(), this, cpuState, stackTrace, 0, 1, + false, false) == B_OK) { stackTraceReference.SetTo(stackTrace, true); } } @@ -680,8 +680,25 @@ ThreadHandler::_HandleSingleStepStep(CpuState* cpuState) case STEP_OVER: { // If we have stepped out of the statement, we're done. - if (!fStepStatement->ContainsAddress(cpuState->InstructionPointer())) + if (!fStepStatement->ContainsAddress(cpuState->InstructionPointer())) { + StackTrace* stackTrace = fThread->GetStackTrace(); + BReference stackTraceReference(stackTrace); + if (stackTrace == NULL && cpuState != NULL) { + if (fDebuggerInterface->GetArchitecture()->CreateStackTrace( + fThread->GetTeam(), this, cpuState, stackTrace, 0, + 1, false, false) == B_OK) { + stackTraceReference.SetTo(stackTrace, true); + } + } + + if (stackTrace != NULL && stackTrace->FrameAt(0) + ->FrameAddress() != fPreviousFrameAddress) { + fThread->SetExecutedSubroutine( + cpuState->InstructionPointer()); + } + return false; + } return _DoStepOver(cpuState); } diff --git a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp index da467da3b0..b40e08c998 100644 --- a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp @@ -68,8 +68,8 @@ DebuggerImageDebugInfo::GetAddressSectionType(target_addr_t address) status_t DebuggerImageDebugInfo::CreateFrame(Image* image, FunctionInstance* functionInstance, CpuState* cpuState, - bool getFullFrameInfo, StackFrame*& _previousFrame, - CpuState*& _previousCpuState) + bool getFullFrameInfo, target_addr_t returnFunctionAddress, + StackFrame*& _previousFrame, CpuState*& _previousCpuState) { return B_UNSUPPORTED; } diff --git a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h index 8c0c520160..bcafebc0f3 100644 --- a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h +++ b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h @@ -36,6 +36,7 @@ public: FunctionInstance* functionInstance, CpuState* cpuState, bool getFullFrameInfo, + target_addr_t returnFunctionAddress, StackFrame*& _previousFrame, CpuState*& _previousCpuState); virtual status_t GetStatement(FunctionDebugInfo* function, diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp index c6aa3ca4ac..b96814da88 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp @@ -41,6 +41,8 @@ #include "FunctionID.h" #include "FunctionInstance.h" #include "GlobalTypeLookup.h" +#include "Image.h" +#include "ImageDebugInfo.h" #include "InstructionInfo.h" #include "LocatableFile.h" #include "Register.h" @@ -51,11 +53,13 @@ #include "StringUtils.h" #include "SymbolInfo.h" #include "TargetAddressRangeList.h" +#include "Team.h" #include "TeamMemory.h" #include "Tracing.h" #include "TypeLookupConstraints.h" #include "UnsupportedLanguage.h" #include "Variable.h" +#include "ValueLocation.h" namespace { @@ -518,7 +522,8 @@ DwarfImageDebugInfo::GetAddressSectionType(target_addr_t address) status_t DwarfImageDebugInfo::CreateFrame(Image* image, FunctionInstance* functionInstance, CpuState* cpuState, - bool getFullFrameInfo, StackFrame*& _frame, CpuState*& _previousCpuState) + bool getFullFrameInfo, target_addr_t returnFunctionAddress, + StackFrame*& _frame, CpuState*& _previousCpuState) { DwarfFunctionDebugInfo* function = dynamic_cast( functionInstance->GetFunctionDebugInfo()); @@ -668,13 +673,14 @@ DwarfImageDebugInfo::CreateFrame(Image* image, instructionPointer, functionInstance->Address() - fRelocationDelta, subprogramEntry->Variables(), subprogramEntry->Blocks()); - // determine if the previously executed instruction was a function - // call to see if we need to potentially retrieve a return value - // as well - if (instructionPointer > functionInstance->Address() - fRelocationDelta) { - _CreateReturnValue(functionInstance, function, frame, - *stackFrameDebugInfo, instructionPointer); + // TODO: re-enable once PIC and false positive issues + // are properly dealt with +#if 0 + if (returnFunctionAddress != 0) { + _CreateReturnValue(returnFunctionAddress, image, frame, + *stackFrameDebugInfo); } +#endif } _frame = frameReference.Detach(); @@ -1084,43 +1090,73 @@ DwarfImageDebugInfo::_CreateLocalVariables(CompilationUnit* unit, status_t -DwarfImageDebugInfo::_CreateReturnValue(FunctionInstance* functionInstance, - DwarfFunctionDebugInfo* function, StackFrame* frame, - DwarfStackFrameDebugInfo& factory, target_addr_t instructionPointer) +DwarfImageDebugInfo::_CreateReturnValue(target_addr_t returnFunctionAddress, + Image* image, StackFrame* frame, DwarfStackFrameDebugInfo& factory) { - DisassembledCode* sourceCode = NULL; - target_size_t bufferSize = std::min(functionInstance->Size(), - (target_size_t)64 * 1024); - void* buffer = malloc(bufferSize); - if (buffer == NULL) - return B_NO_MEMORY; - MemoryDeleter bufferDeleter(buffer); - ssize_t bytesRead = function->GetSpecificImageDebugInfo() - ->ReadCode(functionInstance->Address(), buffer, bufferSize); - if (bytesRead < 0) - return bytesRead; + if (!image->ContainsAddress(returnFunctionAddress)) { + // our current image doesn't contain the target function, + // locate the one which does. + image = image->GetTeam()->ImageByAddress(returnFunctionAddress); + if (image == NULL) + return B_BAD_VALUE; + } - status_t result = fArchitecture->DisassembleCode(function, buffer, - bytesRead, sourceCode); - if (result != B_OK) - return result; + status_t result = B_OK; + FunctionInstance* targetFunction; + if (returnFunctionAddress >= fPLTSectionStart + && returnFunctionAddress < fPLTSectionEnd) { + // TODO: handle resolving PLT entries + // to their target function + return B_UNSUPPORTED; + } - BReference sourceCodeReference(sourceCode, true); - target_addr_t previousStatementAddress = instructionPointer + fRelocationDelta - 1; - Statement* statement = sourceCode->StatementAtAddress( - previousStatementAddress); - if (statement == NULL) - return B_BAD_VALUE; + ImageDebugInfo* imageInfo = image->GetImageDebugInfo(); + targetFunction = imageInfo->FunctionAtAddress(returnFunctionAddress); + if (targetFunction != NULL) { + DwarfFunctionDebugInfo* targetInfo = + dynamic_cast( + targetFunction->GetFunctionDebugInfo()); + if (targetInfo != NULL) { + DIESubprogram* subProgram = targetInfo->SubprogramEntry(); + DIEType* returnType = subProgram->ReturnType(); + if (returnType == NULL) { + // check if we have a specification, and if so, if that has + // a return type + subProgram = dynamic_cast(subProgram->Specification()); + if (subProgram != NULL) + returnType = subProgram->ReturnType(); - TargetAddressRange range = statement->CoveringAddressRange(); - InstructionInfo info; - if (fArchitecture->GetInstructionInfo(range.Start(), info) == B_OK - && info.Type() == INSTRUCTION_TYPE_SUBROUTINE_CALL) { - // TODO: determine where the previous instruction actually jumps to, - // retrieve that function (could potentially be in another image), - // and use its return type to retrieve the return value (will need - // architecture support since function return value passing convention - // is arch-dependent). + // function doesn't return a value, we're done. + if (returnType == NULL) + return B_OK; + } + + uint32 byteSize = 0; + if (returnType->ByteSize() == NULL) { + if (dynamic_cast(returnType) != NULL) + byteSize = fArchitecture->AddressSize(); + } else + byteSize = returnType->ByteSize()->constant; + + ValueLocation* location; + result = fArchitecture->GetReturnAddressLocation(frame, + byteSize, location); + if (result != B_OK) + return result; + + BReference locationReference(location, true); + Variable* variable = NULL; + BReference idReference( + targetFunction->GetFunctionID(), true); + result = factory.CreateReturnValue(idReference, returnType, + location, variable); + if (result != B_OK) + return result; + + BReference variableReference(variable, true); + if (!frame->AddLocalVariable(variable)) + return B_NO_MEMORY; + } } return B_OK; diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h index c03370fdea..203920b11a 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h @@ -64,6 +64,7 @@ public: FunctionInstance* functionInstance, CpuState* cpuState, bool getFullFrameInfo, + target_addr_t returnFunctionAddress, StackFrame*& _frame, CpuState*& _previousCpuState); virtual status_t GetStatement(FunctionDebugInfo* function, @@ -103,11 +104,11 @@ private: const EntryListWrapper& variableEntries, const EntryListWrapper& blockEntries); - status_t _CreateReturnValue(FunctionInstance* instance, - DwarfFunctionDebugInfo* info, + status_t _CreateReturnValue( + target_addr_t returnFunctionAddress, + Image* image, StackFrame* frame, - DwarfStackFrameDebugInfo& factory, - target_addr_t instructionPointer); + DwarfStackFrameDebugInfo& factory); bool _EvaluateBaseTypeConstraints(DIEType* type, const TypeLookupConstraints& constraints); diff --git a/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.cpp index 99853ae8f3..42cef634e4 100644 --- a/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.cpp @@ -1,4 +1,5 @@ /* + * Copyright 2012, Rene Gollent, rene@gollent.com. * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -23,6 +24,7 @@ #include "LocalVariableID.h" #include "Register.h" #include "RegisterMap.h" +#include "ReturnValueID.h" #include "StringUtils.h" #include "Tracing.h" #include "ValueLocation.h" @@ -117,6 +119,47 @@ private: }; +// #pragma mark - DwarfReturnValueID + + +struct DwarfStackFrameDebugInfo::DwarfReturnValueID + : public ReturnValueID { + + DwarfReturnValueID(FunctionID* functionID) + : + fFunctionID(functionID), + fName("(returned)") + { + fFunctionID->AcquireReference(); + } + + virtual ~DwarfReturnValueID() + { + fFunctionID->ReleaseReference(); + } + + virtual bool operator==(const ObjectID& other) const + { + const DwarfReturnValueID* returnValueID + = dynamic_cast(&other); + return returnValueID != NULL + && *fFunctionID == *returnValueID->fFunctionID + && fName == returnValueID->fName; + } + +protected: + virtual uint32 ComputeHashValue() const + { + uint32 hash = fFunctionID->HashValue(); + return hash * 25 + StringUtils::HashValue(fName); + } + +private: + FunctionID* fFunctionID; + const BString fName; +}; + + // #pragma mark - DwarfStackFrameDebugInfo @@ -234,6 +277,39 @@ DwarfStackFrameDebugInfo::CreateLocalVariable(FunctionID* functionID, } +status_t +DwarfStackFrameDebugInfo::CreateReturnValue(FunctionID* functionID, + DIEType* returnType, ValueLocation* location, Variable*& _variable) +{ + if (returnType == NULL) + return B_BAD_VALUE; + + // create the type + DwarfType* type; + status_t error = fTypeFactory->CreateType(returnType, type); + if (error != B_OK) + return error; + BReference typeReference(type, true); + + DwarfReturnValueID* id = new(std::nothrow) DwarfReturnValueID( + functionID); + if (id == NULL) + return B_NO_MEMORY; + + BString name; + name.SetToFormat("%s returned", functionID->FunctionName().String()); + + Variable* variable = new(std::nothrow) Variable(id, name, + type, location); + if (variable == NULL) + return B_NO_MEMORY; + + _variable = variable; + + return B_OK; +} + + status_t DwarfStackFrameDebugInfo::_CreateVariable(ObjectID* id, const BString& name, DIEType* typeEntry, LocationDescription* locationDescription, diff --git a/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.h b/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.h index e55d0d2ed1..3e691308f3 100644 --- a/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfStackFrameDebugInfo.h @@ -1,4 +1,5 @@ /* + * Copyright 2012, Rene Gollent, rene@gollent.com. * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -56,10 +57,16 @@ public: DIEVariable* variableEntry, Variable*& _variable); // returns reference + status_t CreateReturnValue(FunctionID* functionID, + DIEType* returnType, + ValueLocation* location, + Variable*& _variable); + // returns reference private: struct DwarfFunctionParameterID; struct DwarfLocalVariableID; + struct DwarfReturnValueID; private: status_t _CreateVariable(ObjectID* id, diff --git a/src/apps/debugger/debug_info/SpecificImageDebugInfo.h b/src/apps/debugger/debug_info/SpecificImageDebugInfo.h index 7287964ce5..ac655cdf16 100644 --- a/src/apps/debugger/debug_info/SpecificImageDebugInfo.h +++ b/src/apps/debugger/debug_info/SpecificImageDebugInfo.h @@ -56,6 +56,7 @@ public: FunctionInstance* functionInstance, CpuState* cpuState, bool getFullFrameInfo, + target_addr_t returnFunctionAddress, StackFrame*& _Frame, CpuState*& _previousCpuState) = 0; // returns reference to previous frame diff --git a/src/apps/debugger/ids/ReturnValueID.cpp b/src/apps/debugger/ids/ReturnValueID.cpp new file mode 100644 index 0000000000..38e6c841b7 --- /dev/null +++ b/src/apps/debugger/ids/ReturnValueID.cpp @@ -0,0 +1,13 @@ +/* + * Copyright 2012, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ + + +#include "ReturnValueID.h" + + +ReturnValueID::~ReturnValueID() +{ +} + diff --git a/src/apps/debugger/ids/ReturnValueID.h b/src/apps/debugger/ids/ReturnValueID.h new file mode 100644 index 0000000000..021a9175c9 --- /dev/null +++ b/src/apps/debugger/ids/ReturnValueID.h @@ -0,0 +1,18 @@ +/* + * Copyright 2012, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ +#ifndef RETURN_VALUE_ID_H +#define RETURN_VALUE_ID_H + + +#include "ObjectID.h" + + +class ReturnValueID : public ObjectID { +public: + virtual ~ReturnValueID(); +}; + + +#endif // RETURN_VALUE_ID_H diff --git a/src/apps/debugger/jobs/GetStackTraceJob.cpp b/src/apps/debugger/jobs/GetStackTraceJob.cpp index 61a1c724d8..23ce2fc102 100644 --- a/src/apps/debugger/jobs/GetStackTraceJob.cpp +++ b/src/apps/debugger/jobs/GetStackTraceJob.cpp @@ -58,7 +58,8 @@ GetStackTraceJob::Do() // get the stack trace StackTrace* stackTrace; status_t error = fArchitecture->CreateStackTrace(fThread->GetTeam(), this, - fCpuState, stackTrace); + fCpuState, stackTrace, fThread->ExecutedSubroutine() + ? fThread->SubroutineAddress() : 0); if (error != B_OK) return error; BReference stackTraceReference(stackTrace, true); diff --git a/src/apps/debugger/model/Thread.cpp b/src/apps/debugger/model/Thread.cpp index c6692f89e5..63d21e036f 100644 --- a/src/apps/debugger/model/Thread.cpp +++ b/src/apps/debugger/model/Thread.cpp @@ -17,6 +17,8 @@ Thread::Thread(Team* team, thread_id threadID) fTeam(team), fID(threadID), fState(THREAD_STATE_UNKNOWN), + fExecutedSubroutine(false), + fSubroutineAddress(0), fStoppedReason(THREAD_STOPPED_UNKNOWN), fCpuState(NULL), fStackTrace(NULL) @@ -68,6 +70,8 @@ Thread::SetState(uint32 state, uint32 reason, const BString& info) if (fState != THREAD_STATE_STOPPED) { SetCpuState(NULL); SetStackTrace(NULL); + fExecutedSubroutine = false; + fSubroutineAddress = 0; } fTeam->NotifyThreadStateChanged(this); @@ -108,3 +112,12 @@ Thread::SetStackTrace(StackTrace* trace) fTeam->NotifyThreadStackTraceChanged(this); } + + +void +Thread::SetExecutedSubroutine(target_addr_t address) +{ + fExecutedSubroutine = true; + fSubroutineAddress = address; +} + diff --git a/src/apps/debugger/model/Thread.h b/src/apps/debugger/model/Thread.h index e34064fffd..1cba07ff0c 100644 --- a/src/apps/debugger/model/Thread.h +++ b/src/apps/debugger/model/Thread.h @@ -11,6 +11,8 @@ #include #include +#include "types/Types.h" + class CpuState; class StackTrace; @@ -67,11 +69,19 @@ public: StackTrace* GetStackTrace() const { return fStackTrace; } void SetStackTrace(StackTrace* trace); + bool ExecutedSubroutine() const + { return fExecutedSubroutine; } + target_addr_t SubroutineAddress() const + { return fSubroutineAddress; } + void SetExecutedSubroutine(target_addr_t address); + private: Team* fTeam; thread_id fID; BString fName; uint32 fState; + bool fExecutedSubroutine; + target_addr_t fSubroutineAddress; uint32 fStoppedReason; BString fStoppedReasonInfo; CpuState* fCpuState; diff --git a/src/apps/deskbar/BarApp.cpp b/src/apps/deskbar/BarApp.cpp index af7372d696..9c12a2798a 100644 --- a/src/apps/deskbar/BarApp.cpp +++ b/src/apps/deskbar/BarApp.cpp @@ -302,6 +302,8 @@ TBarApp::InitSettings() theDir.CreateFile(settingsFileName, fSettingsFile); } + filePath = dirPath; + filePath.Append(clockSettingsFileName); fClockSettingsFile = new BFile(filePath.Path(), O_RDWR); if (fClockSettingsFile->InitCheck() != B_OK) { BDirectory theDir(dirPath.Path()); diff --git a/src/preferences/appearance/APRWindow.cpp b/src/preferences/appearance/APRWindow.cpp index 61203bcacb..87afe9487c 100644 --- a/src/preferences/appearance/APRWindow.cpp +++ b/src/preferences/appearance/APRWindow.cpp @@ -21,9 +21,9 @@ #include "AntialiasingSettingsView.h" #include "APRView.h" -#include "LookAndFeelSettingsView.h" #include "defs.h" #include "FontView.h" +#include "LookAndFeelSettingsView.h" #undef B_TRANSLATION_CONTEXT @@ -50,19 +50,19 @@ APRWindow::APRWindow(BRect frame) BTabView* tabView = new BTabView("tabview", B_WIDTH_FROM_LABEL); - fLookAndFeelSettings = new LookAndFeelSettingsView( - B_TRANSLATE("Look and feel")); - fFontSettings = new FontView(B_TRANSLATE("Fonts")); fColorsView = new APRView(B_TRANSLATE("Colors")); + fLookAndFeelSettings = new LookAndFeelSettingsView( + B_TRANSLATE("Look and feel")); + fAntialiasingSettings = new AntialiasingSettingsView( B_TRANSLATE("Antialiasing")); - tabView->AddTab(fLookAndFeelSettings); tabView->AddTab(fFontSettings); tabView->AddTab(fColorsView); + tabView->AddTab(fLookAndFeelSettings); tabView->AddTab(fAntialiasingSettings); _UpdateButtons(); @@ -91,8 +91,8 @@ APRWindow::MessageReceived(BMessage *message) case kMsgSetDefaults: fFontSettings->SetDefaults(); fColorsView->SetDefaults(); - fAntialiasingSettings->SetDefaults(); fLookAndFeelSettings->SetDefaults(); + fAntialiasingSettings->SetDefaults(); _UpdateButtons(); break; @@ -100,8 +100,8 @@ APRWindow::MessageReceived(BMessage *message) case kMsgRevert: fColorsView->Revert(); fAntialiasingSettings->Revert(); - fFontSettings->Revert(); fLookAndFeelSettings->Revert(); + fFontSettings->Revert(); _UpdateButtons(); break; @@ -128,10 +128,10 @@ APRWindow::_IsDefaultable() const // printf("colors defaultable: %d\n", fColorsView->IsDefaultable()); // printf("AA defaultable: %d\n", fAntialiasingSettings->IsDefaultable()); // printf("decor defaultable: %d\n", fLookAndFeelSettings->IsDefaultable()); - return fColorsView->IsDefaultable() - || fFontSettings->IsDefaultable() - || fAntialiasingSettings->IsDefaultable() - || fLookAndFeelSettings->IsDefaultable(); + return fFontSettings->IsDefaultable() + || fColorsView->IsDefaultable() + || fLookAndFeelSettings->IsDefaultable() + || fAntialiasingSettings->IsDefaultable(); } @@ -142,8 +142,8 @@ APRWindow::_IsRevertable() const // printf("colors revertable: %d\n", fColorsView->IsRevertable()); // printf("AA revertable: %d\n", fAntialiasingSettings->IsRevertable()); // printf("decor revertable: %d\n", fLookAndFeelSettings->IsRevertable()); - return fColorsView->IsRevertable() - || fFontSettings->IsRevertable() - || fAntialiasingSettings->IsRevertable() - || fLookAndFeelSettings->IsRevertable(); + return fFontSettings->IsRevertable() + || fColorsView->IsRevertable() + || fLookAndFeelSettings->IsRevertable() + || fAntialiasingSettings->IsRevertable(); }