Merge branch 'master' into sam460ex
This commit is contained in:
@@ -11,9 +11,9 @@ KernelAddon intel_extreme :
|
||||
driver.cpp
|
||||
device.cpp
|
||||
intel_extreme.cpp
|
||||
power.cpp
|
||||
|
||||
kernel_cpp.cpp
|
||||
|
||||
: libgraphicscommon.a
|
||||
;
|
||||
|
||||
|
||||
@@ -10,16 +10,16 @@
|
||||
#include "intel_extreme.h"
|
||||
|
||||
#include "AreaKeeper.h"
|
||||
#include "driver.h"
|
||||
#include "utility.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <driver_settings.h>
|
||||
#include <util/kernel_cpp.h>
|
||||
#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();
|
||||
|
||||
@@ -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, [email protected]
|
||||
*/
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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, [email protected]
|
||||
*/
|
||||
#ifndef _INTEL_POWER_H_
|
||||
#define _INTEL_POWER_H_
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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_ */
|
||||
@@ -124,9 +124,10 @@ Application Debugger :
|
||||
|
||||
# ids
|
||||
FunctionID.cpp
|
||||
FunctionParameterID.cpp
|
||||
LocalVariableID.cpp
|
||||
ObjectID.cpp
|
||||
FunctionParameterID.cpp
|
||||
ReturnValueID.cpp
|
||||
|
||||
# jobs
|
||||
GetCPUStateJob.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<CpuState> 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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<ValueLocation> 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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -12,6 +12,36 @@
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#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<CpuStateX86*>(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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 ] ;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<StackTrace> 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<DwarfFunctionDebugInfo*>(
|
||||
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<DisassembledCode> 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<DwarfFunctionDebugInfo*>(
|
||||
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<DIESubprogram*>(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<DIEAddressingType*>(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<ValueLocation> locationReference(location, true);
|
||||
Variable* variable = NULL;
|
||||
BReference<FunctionID> idReference(
|
||||
targetFunction->GetFunctionID(), true);
|
||||
result = factory.CreateReturnValue(idReference, returnType,
|
||||
location, variable);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
BReference<Variable> variableReference(variable, true);
|
||||
if (!frame->AddLocalVariable(variable))
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<const DwarfReturnValueID*>(&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<DwarfType> 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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2012, Rene Gollent, rene@gollent.com.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "ReturnValueID.h"
|
||||
|
||||
|
||||
ReturnValueID::~ReturnValueID()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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<StackTrace> stackTraceReference(stackTrace, true);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <Referenceable.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user