* Introduce TeamMemoryBlock[Manager]. These provide an interface to raw memory
page data of the target team. * Jobs: Add RetrieveMemoryBlockJob which performs a background read of the target team's memory. Used by InspectRequested() to perform the actual work. * TeamDebugger: Added InspectRequested() hooks to allow clients to ask for a memory read to be performed. * Introduce InspectorWindow and MemoryView to form the basis of a memory inspector. As yet these are more or less stubs and not yet hooked in. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42080 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -20,6 +20,7 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) source_language ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) types ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface gui ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface gui inspector_window ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface gui model ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface gui team_window ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface gui teams_window ] ;
|
||||
@@ -54,6 +55,7 @@ Application Debugger :
|
||||
BreakpointManager.cpp
|
||||
Debugger.cpp
|
||||
Jobs.cpp
|
||||
TeamMemoryBlockManager.cpp
|
||||
TeamDebugger.cpp
|
||||
ThreadHandler.cpp
|
||||
Worker.cpp
|
||||
@@ -127,6 +129,7 @@ Application Debugger :
|
||||
UserBreakpoint.cpp
|
||||
Team.cpp
|
||||
TeamMemory.cpp
|
||||
TeamMemoryBlock.cpp
|
||||
Thread.cpp
|
||||
ThreadInfo.cpp
|
||||
Type.cpp
|
||||
@@ -167,6 +170,10 @@ Application Debugger :
|
||||
VariablesViewState.cpp
|
||||
VariablesViewStateHistory.cpp
|
||||
|
||||
# user_interface/gui/inspector_window
|
||||
InspectorWindow.cpp
|
||||
MemoryView.cpp
|
||||
|
||||
# user_interface/gui/teams_window
|
||||
TeamsWindow.cpp
|
||||
TeamsListView.cpp
|
||||
@@ -253,7 +260,7 @@ Application Debugger :
|
||||
libshared.a
|
||||
|
||||
$(TARGET_LIBSTDC++)
|
||||
be tracker libdebug.so
|
||||
be tracker libdebug.so libshared.a libexpression_parser.a libmapm.a
|
||||
|
||||
: Debugger.rdef
|
||||
;
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "StackFrameValues.h"
|
||||
#include "StackTrace.h"
|
||||
#include "Team.h"
|
||||
#include "TeamMemory.h"
|
||||
#include "TeamMemoryBlock.h"
|
||||
#include "TeamDebugInfo.h"
|
||||
#include "Thread.h"
|
||||
#include "Tracing.h"
|
||||
@@ -633,3 +635,41 @@ ResolveValueNodeValueJob::_ResolveParentNodeValue(ValueNode* parentNode)
|
||||
return nodeResolutionState != VALUE_NODE_UNRESOLVED
|
||||
? nodeResolutionState : B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
RetrieveMemoryBlockJob::RetrieveMemoryBlockJob(TeamMemory* teamMemory,
|
||||
TeamMemoryBlock* memoryBlock)
|
||||
:
|
||||
fKey(memoryBlock, JOB_TYPE_GET_MEMORY_BLOCK),
|
||||
fTeamMemory(teamMemory),
|
||||
fMemoryBlock(memoryBlock)
|
||||
{
|
||||
fMemoryBlock->AcquireReference();
|
||||
}
|
||||
|
||||
|
||||
RetrieveMemoryBlockJob::~RetrieveMemoryBlockJob()
|
||||
{
|
||||
fMemoryBlock->ReleaseReference();
|
||||
}
|
||||
|
||||
|
||||
const JobKey&
|
||||
RetrieveMemoryBlockJob::Key() const
|
||||
{
|
||||
return fKey;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
RetrieveMemoryBlockJob::Do()
|
||||
{
|
||||
|
||||
ssize_t result = fTeamMemory->ReadMemory(fMemoryBlock->BaseAddress(),
|
||||
fMemoryBlock->Data(), fMemoryBlock->Size());
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
fMemoryBlock->MarkValid();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Copyright 2011, Rene Gollent, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef JOBS_H
|
||||
@@ -7,6 +8,7 @@
|
||||
|
||||
|
||||
#include "ImageDebugInfoProvider.h"
|
||||
#include "Types.h"
|
||||
#include "Worker.h"
|
||||
|
||||
|
||||
@@ -20,6 +22,8 @@ class Image;
|
||||
class StackFrame;
|
||||
class StackFrameValues;
|
||||
class Team;
|
||||
class TeamMemory;
|
||||
class TeamMemoryBlock;
|
||||
class Thread;
|
||||
class Type;
|
||||
class TypeComponentPath;
|
||||
@@ -38,7 +42,8 @@ enum {
|
||||
JOB_TYPE_LOAD_IMAGE_DEBUG_INFO,
|
||||
JOB_TYPE_LOAD_SOURCE_CODE,
|
||||
JOB_TYPE_GET_STACK_FRAME_VALUE,
|
||||
JOB_TYPE_RESOLVE_VALUE_NODE_VALUE
|
||||
JOB_TYPE_RESOLVE_VALUE_NODE_VALUE,
|
||||
JOB_TYPE_GET_MEMORY_BLOCK
|
||||
};
|
||||
|
||||
|
||||
@@ -177,4 +182,21 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class RetrieveMemoryBlockJob : public Job {
|
||||
public:
|
||||
RetrieveMemoryBlockJob(
|
||||
TeamMemory* teamMemory,
|
||||
TeamMemoryBlock* memoryBlock);
|
||||
virtual ~RetrieveMemoryBlockJob();
|
||||
|
||||
virtual const JobKey& Key() const;
|
||||
virtual status_t Do();
|
||||
|
||||
private:
|
||||
SimpleJobKey fKey;
|
||||
TeamMemory* fTeamMemory;
|
||||
TeamMemoryBlock* fMemoryBlock;
|
||||
};
|
||||
|
||||
|
||||
#endif // JOBS_H
|
||||
|
||||
@@ -44,7 +44,9 @@ enum {
|
||||
MSG_TEAM_DEBUGGER_QUIT = 'dbqt',
|
||||
MSG_SHOW_TEAMS_WINDOW = 'stsw',
|
||||
MSG_TEAMS_WINDOW_CLOSED = 'tswc',
|
||||
MSG_DEBUG_THIS_TEAM = 'dbtt'
|
||||
MSG_DEBUG_THIS_TEAM = 'dbtt',
|
||||
MSG_INSPECTOR_WINDOW_CLOSED = 'irwc',
|
||||
MSG_INSPECT_ADDRESS = 'isad'
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <Message.h>
|
||||
|
||||
#include <ExpressionParser.h>
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "debug_utils.h"
|
||||
@@ -37,6 +38,8 @@
|
||||
#include "Statement.h"
|
||||
#include "SymbolInfo.h"
|
||||
#include "TeamDebugInfo.h"
|
||||
#include "TeamMemoryBlock.h"
|
||||
#include "TeamMemoryBlockManager.h"
|
||||
#include "TeamSettings.h"
|
||||
#include "Tracing.h"
|
||||
#include "ValueNode.h"
|
||||
@@ -446,6 +449,26 @@ TeamDebugger::MessageReceived(BMessage* message)
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_INSPECT_ADDRESS:
|
||||
{
|
||||
TeamMemoryBlock::Listener* listener;
|
||||
if (message->FindPointer("listener",
|
||||
reinterpret_cast<void **>(&listener)) != B_OK) {
|
||||
break;
|
||||
}
|
||||
|
||||
const char* addressExpression;
|
||||
target_addr_t address;
|
||||
if (message->FindString("addressExpression",
|
||||
&addressExpression) == B_OK) {
|
||||
_HandleInspectAddress(addressExpression, listener);
|
||||
} else if (message->FindUInt64("address",
|
||||
&address) == B_OK) {
|
||||
_HandleInspectAddress(address, listener);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_THREAD_STATE_CHANGED:
|
||||
{
|
||||
int32 threadID;
|
||||
@@ -661,6 +684,28 @@ TeamDebugger::ClearBreakpointRequested(UserBreakpoint* breakpoint)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::InspectRequested(const char* addressExpression,
|
||||
TeamMemoryBlock::Listener *listener)
|
||||
{
|
||||
BMessage message(MSG_INSPECT_ADDRESS);
|
||||
message.AddString("addressExpression", addressExpression);
|
||||
message.AddPointer("listener", listener);
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::InspectRequested(target_addr_t address,
|
||||
TeamMemoryBlock::Listener *listener)
|
||||
{
|
||||
BMessage message(MSG_INSPECT_ADDRESS);
|
||||
message.AddUInt64("address", address);
|
||||
message.AddPointer("listener", listener);
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TeamDebugger::UserInterfaceQuitRequested()
|
||||
{
|
||||
@@ -1243,6 +1288,68 @@ TeamDebugger::_HandleClearUserBreakpoint(UserBreakpoint* breakpoint)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::_HandleInspectAddress(const char* addressExpression,
|
||||
TeamMemoryBlock::Listener* listener)
|
||||
{
|
||||
TRACE_CONTROL("TeamDebugger::_HandleInspectAddress(%s, %p)\n",
|
||||
addressExpression, listener);
|
||||
|
||||
ExpressionParser parser;
|
||||
parser.SetSupportHexInput(true);
|
||||
target_addr_t address = 0LL;
|
||||
try {
|
||||
address = parser.EvaluateToInt64(addressExpression);
|
||||
} catch(ParseException parseError) {
|
||||
_NotifyUser("Inspect Address", "Failed to parse address: %s",
|
||||
parseError.message.String());
|
||||
return;
|
||||
} catch(...) {
|
||||
_NotifyUser("Inspect Address", "Unknown error while parsing address");
|
||||
return;
|
||||
}
|
||||
|
||||
_HandleInspectAddress(address, listener);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::_HandleInspectAddress(target_addr_t address,
|
||||
TeamMemoryBlock::Listener* listener)
|
||||
{
|
||||
TRACE_CONTROL("TeamDebugger::_HandleInspectAddress(" B_PRIx64 ", %p)\n",
|
||||
addressExpression, listener);
|
||||
|
||||
TeamMemoryBlock* memoryBlock = fMemoryBlockManager
|
||||
->GetMemoryBlock(address);
|
||||
|
||||
if (memoryBlock == NULL) {
|
||||
_NotifyUser("Inspect Address", "Failed to allocate memory block");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!memoryBlock->HasListener(listener))
|
||||
memoryBlock->AddListener(listener);
|
||||
|
||||
if (!memoryBlock->IsValid()) {
|
||||
AutoLocker< ::Team> teamLocker(fTeam);
|
||||
|
||||
TeamMemory* memory = fTeam->GetTeamMemory();
|
||||
// schedule the job
|
||||
status_t result;
|
||||
if ((result = fWorker->ScheduleJob(
|
||||
new(std::nothrow) RetrieveMemoryBlockJob(memory, memoryBlock),
|
||||
this)) != B_OK) {
|
||||
memoryBlock->ReleaseReference();
|
||||
_NotifyUser("Inspect Address", "Failed to retrieve memory data: %s",
|
||||
strerror(result));
|
||||
}
|
||||
} else
|
||||
memoryBlock->NotifyDataRetrieved();
|
||||
|
||||
}
|
||||
|
||||
|
||||
ThreadHandler*
|
||||
TeamDebugger::_GetThreadHandler(thread_id threadID)
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@ class DebuggerInterface;
|
||||
class FileManager;
|
||||
class SettingsManager;
|
||||
class TeamDebugInfo;
|
||||
class TeamMemoryBlockManager;
|
||||
|
||||
|
||||
class TeamDebugger : public BLooper, private UserInterfaceListener,
|
||||
@@ -65,6 +66,10 @@ private:
|
||||
virtual void ClearBreakpointRequested(target_addr_t address);
|
||||
virtual void ClearBreakpointRequested(
|
||||
UserBreakpoint* breakpoint);
|
||||
virtual void InspectRequested(target_addr_t address,
|
||||
TeamMemoryBlock::Listener* listener);
|
||||
virtual void InspectRequested(const char* addressExpression,
|
||||
TeamMemoryBlock::Listener* listener);
|
||||
virtual bool UserInterfaceQuitRequested();
|
||||
|
||||
// JobListener
|
||||
@@ -118,6 +123,13 @@ private:
|
||||
void _HandleClearUserBreakpoint(
|
||||
UserBreakpoint* breakpoint);
|
||||
|
||||
void _HandleInspectAddress(
|
||||
target_addr_t address,
|
||||
TeamMemoryBlock::Listener* listener);
|
||||
void _HandleInspectAddress(
|
||||
const char* addressExpression,
|
||||
TeamMemoryBlock::Listener* listener);
|
||||
|
||||
ThreadHandler* _GetThreadHandler(thread_id threadID);
|
||||
|
||||
status_t _AddImage(const ImageInfo& imageInfo,
|
||||
@@ -142,6 +154,8 @@ private:
|
||||
FileManager* fFileManager;
|
||||
Worker* fWorker;
|
||||
BreakpointManager* fBreakpointManager;
|
||||
TeamMemoryBlockManager*
|
||||
fMemoryBlockManager;
|
||||
thread_id fDebugEventListener;
|
||||
UserInterface* fUserInterface;
|
||||
volatile bool fTerminating;
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright 2011, Rene Gollent, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "TeamMemoryBlockManager.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "TeamMemoryBlock.h"
|
||||
|
||||
|
||||
struct TeamMemoryBlockManager::Key {
|
||||
target_addr_t address;
|
||||
|
||||
Key(target_addr_t address)
|
||||
:
|
||||
address(address)
|
||||
{
|
||||
}
|
||||
|
||||
uint32 HashValue() const
|
||||
{
|
||||
return (uint32)address;
|
||||
}
|
||||
|
||||
bool operator==(const Key& other) const
|
||||
{
|
||||
return address == other.address;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct TeamMemoryBlockManager::MemoryBlockEntry : Key {
|
||||
TeamMemoryBlock* block;
|
||||
MemoryBlockEntry* next;
|
||||
|
||||
MemoryBlockEntry(TeamMemoryBlock* block)
|
||||
:
|
||||
Key(block->BaseAddress()),
|
||||
block(block)
|
||||
{
|
||||
block->AcquireReference();
|
||||
}
|
||||
|
||||
~MemoryBlockEntry()
|
||||
{
|
||||
block->ReleaseReference();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct TeamMemoryBlockManager::MemoryBlockHashDefinition {
|
||||
typedef Key KeyType;
|
||||
typedef MemoryBlockEntry ValueType;
|
||||
|
||||
size_t HashKey(const Key& key) const
|
||||
{
|
||||
return key.HashValue();
|
||||
}
|
||||
|
||||
size_t Hash(const MemoryBlockEntry* value) const
|
||||
{
|
||||
return value->HashValue();
|
||||
}
|
||||
|
||||
bool Compare(const Key& key, const MemoryBlockEntry* value) const
|
||||
{
|
||||
return key == *value;
|
||||
}
|
||||
|
||||
MemoryBlockEntry*& GetLink(MemoryBlockEntry* value) const
|
||||
{
|
||||
return value->next;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TeamMemoryBlockManager::TeamMemoryBlockManager()
|
||||
:
|
||||
fActiveBlocks(NULL),
|
||||
fDeadBlocks(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TeamMemoryBlockManager::~TeamMemoryBlockManager()
|
||||
{
|
||||
_Cleanup();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TeamMemoryBlockManager::Init()
|
||||
{
|
||||
status_t result = fLock.InitCheck();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
fActiveBlocks = new(std::nothrow) MemoryBlockTable();
|
||||
if (fActiveBlocks == NULL)
|
||||
return B_NO_MEMORY;
|
||||
ObjectDeleter<MemoryBlockTable> activeDeleter(fActiveBlocks);
|
||||
result = fActiveBlocks->Init();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
fDeadBlocks = new(std::nothrow) MemoryBlockTable();
|
||||
if (fDeadBlocks == NULL)
|
||||
return B_NO_MEMORY;
|
||||
ObjectDeleter<MemoryBlockTable> deadDeleter(fDeadBlocks);
|
||||
result = fDeadBlocks->Init();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
activeDeleter.Detach();
|
||||
deadDeleter.Detach();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
TeamMemoryBlock*
|
||||
TeamMemoryBlockManager::GetMemoryBlock(target_addr_t address)
|
||||
{
|
||||
AutoLocker<BLocker> lock(fLock);
|
||||
|
||||
address &= ~B_PAGE_SIZE - 1;
|
||||
MemoryBlockEntry* entry = fActiveBlocks->Lookup(address);
|
||||
if (entry == NULL) {
|
||||
TeamMemoryBlock* block = new(std::nothrow) TeamMemoryBlock(address,
|
||||
this);
|
||||
if (block == NULL)
|
||||
return NULL;
|
||||
|
||||
entry = new(std::nothrow) MemoryBlockEntry(block);
|
||||
if (entry == NULL) {
|
||||
delete block;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fActiveBlocks->Insert(entry);
|
||||
}
|
||||
|
||||
int32 refCount = entry->block->AcquireReference();
|
||||
if (refCount == 0) {
|
||||
// this block already had its last reference released,
|
||||
// move it to the dead list and retrieve a new one instead.
|
||||
_MarkDeadBlock(address);
|
||||
return GetMemoryBlock(address);
|
||||
}
|
||||
|
||||
return entry->block;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamMemoryBlockManager::_Cleanup()
|
||||
{
|
||||
if (fActiveBlocks != NULL) {
|
||||
MemoryBlockEntry* entry = fActiveBlocks->Clear(true);
|
||||
|
||||
while (entry != NULL) {
|
||||
MemoryBlockEntry* next = entry->next;
|
||||
delete entry;
|
||||
entry = next;
|
||||
}
|
||||
|
||||
delete fActiveBlocks;
|
||||
fActiveBlocks = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamMemoryBlockManager::_MarkDeadBlock(target_addr_t address)
|
||||
{
|
||||
AutoLocker<BLocker> lock(fLock);
|
||||
MemoryBlockEntry* entry = fActiveBlocks->Lookup(address);
|
||||
if (entry != NULL) {
|
||||
fActiveBlocks->Remove(entry);
|
||||
fDeadBlocks->Insert(entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamMemoryBlockManager::_RemoveBlock(target_addr_t address)
|
||||
{
|
||||
AutoLocker<BLocker> lock(fLock);
|
||||
MemoryBlockEntry* entry = fActiveBlocks->Lookup(address);
|
||||
if (entry != NULL) {
|
||||
fActiveBlocks->Remove(entry);
|
||||
delete entry;
|
||||
return;
|
||||
}
|
||||
|
||||
entry = fDeadBlocks->Lookup(address);
|
||||
if (entry != NULL) {
|
||||
fDeadBlocks->Remove(entry);
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2011, Rene Gollent, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef TEAM_MEMORY_BLOCK_MANAGER_H
|
||||
#define TEAM_MEMORY_BLOCK_MANAGER_H
|
||||
|
||||
|
||||
#include <Locker.h>
|
||||
#include <Referenceable.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
struct MemoryBlockHashDefinition;
|
||||
class TeamMemoryBlock;
|
||||
|
||||
|
||||
class TeamMemoryBlockManager
|
||||
{
|
||||
public:
|
||||
TeamMemoryBlockManager();
|
||||
~TeamMemoryBlockManager();
|
||||
|
||||
status_t Init();
|
||||
|
||||
TeamMemoryBlock* GetMemoryBlock(target_addr_t address);
|
||||
|
||||
private:
|
||||
struct Key;
|
||||
struct MemoryBlockEntry;
|
||||
struct MemoryBlockHashDefinition;
|
||||
typedef BOpenHashTable<MemoryBlockHashDefinition> MemoryBlockTable;
|
||||
|
||||
private:
|
||||
void _Cleanup();
|
||||
void _MarkDeadBlock(target_addr_t address);
|
||||
void _RemoveBlock(target_addr_t address);
|
||||
|
||||
private:
|
||||
friend class TeamMemoryBlock;
|
||||
|
||||
private:
|
||||
BLocker fLock;
|
||||
MemoryBlockTable* fActiveBlocks;
|
||||
MemoryBlockTable* fDeadBlocks;
|
||||
};
|
||||
|
||||
|
||||
#endif // TEAM_MEMORY_BLOCK_MANAGER_H
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2011, Rene Gollent, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "TeamMemoryBlock.h"
|
||||
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "TeamMemoryBlockManager.h"
|
||||
|
||||
|
||||
// #pragma mark - TeamMemoryBlock
|
||||
|
||||
|
||||
TeamMemoryBlock::TeamMemoryBlock(target_addr_t baseAddress,
|
||||
TeamMemoryBlockManager* manager)
|
||||
:
|
||||
fValid(false),
|
||||
fBaseAddress(baseAddress),
|
||||
fBlockManager(manager)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TeamMemoryBlock::~TeamMemoryBlock()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamMemoryBlock::AddListener(Listener* listener)
|
||||
{
|
||||
AutoLocker<BLocker> lock(fLock);
|
||||
fListeners.Add(listener);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TeamMemoryBlock::HasListener(Listener* listener)
|
||||
{
|
||||
AutoLocker<BLocker> lock(fLock);
|
||||
ListenerList::Iterator iterator = fListeners.GetIterator();
|
||||
while (iterator.HasNext()) {
|
||||
if (iterator.Next() == listener)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamMemoryBlock::RemoveListener(Listener* listener)
|
||||
{
|
||||
AutoLocker<BLocker> lock(fLock);
|
||||
fListeners.Remove(listener);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamMemoryBlock::MarkValid()
|
||||
{
|
||||
fValid = true;
|
||||
NotifyDataRetrieved();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamMemoryBlock::Invalidate()
|
||||
{
|
||||
fValid = false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamMemoryBlock::NotifyDataRetrieved()
|
||||
{
|
||||
for (ListenerList::Iterator it = fListeners.GetIterator();
|
||||
Listener* listener = it.Next();) {
|
||||
listener->MemoryBlockRetrieved(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamMemoryBlock::LastReferenceReleased()
|
||||
{
|
||||
fBlockManager->_RemoveBlock(fBaseAddress);
|
||||
|
||||
BReferenceable::LastReferenceReleased();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - TeamMemoryBlock
|
||||
|
||||
|
||||
TeamMemoryBlock::Listener::~Listener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamMemoryBlock::Listener::MemoryBlockRetrieved(TeamMemoryBlock* block)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2011, Rene Gollent, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef TEAM_MEMORY_BLOCK_H
|
||||
#define TEAM_MEMORY_BLOCK_H
|
||||
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include <Locker.h>
|
||||
#include <Referenceable.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
|
||||
class TeamMemoryBlockManager;
|
||||
|
||||
|
||||
class TeamMemoryBlock : public BReferenceable {
|
||||
public:
|
||||
class Listener;
|
||||
|
||||
public:
|
||||
TeamMemoryBlock(target_addr_t baseAddress,
|
||||
TeamMemoryBlockManager* manager);
|
||||
~TeamMemoryBlock();
|
||||
|
||||
void AddListener(Listener* listener);
|
||||
bool HasListener(Listener* listener);
|
||||
void RemoveListener(Listener* listener);
|
||||
|
||||
bool IsValid() const { return fValid; };
|
||||
void MarkValid();
|
||||
void Invalidate();
|
||||
|
||||
target_addr_t BaseAddress() const { return fBaseAddress; };
|
||||
uint8* Data() { return fData; };
|
||||
size_t Size() const { return sizeof(fData); };
|
||||
|
||||
void NotifyDataRetrieved();
|
||||
|
||||
protected:
|
||||
virtual void LastReferenceReleased();
|
||||
|
||||
private:
|
||||
typedef DoublyLinkedList<Listener> ListenerList;
|
||||
|
||||
private:
|
||||
bool fValid;
|
||||
target_addr_t fBaseAddress;
|
||||
uint8 fData[B_PAGE_SIZE];
|
||||
ListenerList fListeners;
|
||||
TeamMemoryBlockManager*
|
||||
fBlockManager;
|
||||
BLocker fLock;
|
||||
};
|
||||
|
||||
|
||||
class TeamMemoryBlock::Listener : public DoublyLinkedListLinkImpl<Listener> {
|
||||
public:
|
||||
virtual ~Listener();
|
||||
|
||||
virtual void MemoryBlockRetrieved(TeamMemoryBlock* block);
|
||||
};
|
||||
|
||||
|
||||
#endif // TEAM_MEMORY_BLOCK_H
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "TeamMemoryBlock.h"
|
||||
#include "Types.h"
|
||||
|
||||
|
||||
@@ -82,6 +83,13 @@ public:
|
||||
UserBreakpoint* breakpoint) = 0;
|
||||
// TODO: Consolidate those!
|
||||
|
||||
virtual void InspectRequested(
|
||||
target_addr_t address,
|
||||
TeamMemoryBlock::Listener* listener) = 0;
|
||||
virtual void InspectRequested(
|
||||
const char* addressExpression,
|
||||
TeamMemoryBlock::Listener* listener) = 0;
|
||||
|
||||
virtual bool UserInterfaceQuitRequested() = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2011, Rene Gollent, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "InspectorWindow.h"
|
||||
|
||||
#include <Application.h>
|
||||
#include <Button.h>
|
||||
#include <LayoutBuilder.h>
|
||||
#include <ScrollView.h>
|
||||
#include <TextControl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "MemoryView.h"
|
||||
#include "MessageCodes.h"
|
||||
#include "UserInterface.h"
|
||||
|
||||
|
||||
InspectorWindow::InspectorWindow(UserInterfaceListener* listener)
|
||||
:
|
||||
BWindow(BRect(100, 100, 500, 250), "Inspector", B_DOCUMENT_WINDOW,
|
||||
B_ASYNCHRONOUS_CONTROLS),
|
||||
fListener(listener)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
InspectorWindow::~InspectorWindow()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/* static */ InspectorWindow*
|
||||
InspectorWindow::Create(UserInterfaceListener* listener)
|
||||
{
|
||||
InspectorWindow* self = new InspectorWindow(listener);
|
||||
|
||||
try {
|
||||
self->_Init();
|
||||
} catch (...) {
|
||||
delete self;
|
||||
throw;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InspectorWindow::_Init()
|
||||
{
|
||||
BLayoutBuilder::Group<>(this, B_VERTICAL)
|
||||
.Add(fAddressInput = new BTextControl("addrInput",
|
||||
"Target Address:", "",
|
||||
new BMessage(MSG_INSPECT_ADDRESS)))
|
||||
.Add(fMemoryView = new MemoryView(NULL, NULL))
|
||||
.End();
|
||||
|
||||
fAddressInput->SetTarget(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
InspectorWindow::MessageReceived(BMessage* msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case MSG_INSPECT_ADDRESS:
|
||||
{
|
||||
const char* addressExpression = fAddressInput->Text();
|
||||
fListener->InspectRequested(addressExpression, this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
InspectorWindow::QuitRequested()
|
||||
{
|
||||
be_app_messenger.SendMessage(MSG_INSPECTOR_WINDOW_CLOSED);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InspectorWindow::MemoryBlockRetrieved(TeamMemoryBlock* block)
|
||||
{
|
||||
// TODO: implement
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2011, Rene Gollent, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef INSPECTOR_WINDOW_H
|
||||
#define INSPECTOR_WINDOW_H
|
||||
|
||||
|
||||
#include <Window.h>
|
||||
|
||||
#include "TeamMemoryBlock.h"
|
||||
#include "Types.h"
|
||||
|
||||
|
||||
class BButton;
|
||||
class BTextControl;
|
||||
class MemoryView;
|
||||
class UserInterfaceListener;
|
||||
|
||||
|
||||
class InspectorWindow : public BWindow,
|
||||
public TeamMemoryBlock::Listener {
|
||||
public:
|
||||
InspectorWindow(
|
||||
UserInterfaceListener* listener);
|
||||
virtual ~InspectorWindow();
|
||||
|
||||
static InspectorWindow* Create(UserInterfaceListener* listener);
|
||||
// throws
|
||||
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual bool QuitRequested();
|
||||
|
||||
virtual void MemoryBlockRetrieved(TeamMemoryBlock* block);
|
||||
|
||||
private:
|
||||
void _Init();
|
||||
|
||||
private:
|
||||
UserInterfaceListener* fListener;
|
||||
BTextControl* fAddressInput;
|
||||
MemoryView* fMemoryView;
|
||||
};
|
||||
|
||||
#endif // INSPECTOR_WINDOW_H
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2011, Rene Gollent, [email protected]. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "MemoryView.h"
|
||||
|
||||
|
||||
MemoryView::MemoryView(Team* team, Listener* listener)
|
||||
:
|
||||
BView("memoryView", B_WILL_DRAW | B_SUBPIXEL_PRECISE),
|
||||
fTeam(team),
|
||||
fListener(listener)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
MemoryView::~MemoryView()
|
||||
{
|
||||
UnsetListener();
|
||||
}
|
||||
|
||||
|
||||
/*static */ MemoryView*
|
||||
MemoryView::Create(Team* team, Listener* listener)
|
||||
{
|
||||
MemoryView* self = new MemoryView(team, listener);
|
||||
|
||||
try {
|
||||
self->_Init();
|
||||
} catch(...) {
|
||||
delete self;
|
||||
throw;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MemoryView::UnsetListener()
|
||||
{
|
||||
fListener = NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MemoryView::SetTargetAddress(target_addr_t address)
|
||||
{
|
||||
fTargetAddress = address;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MemoryView::TargetAddressChanged(target_addr_t address)
|
||||
{
|
||||
SetTargetAddress(address);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MemoryView::TargetedByScrollView(BScrollView* scrollView)
|
||||
{
|
||||
BView::TargetedByScrollView(scrollView);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MemoryView::Draw(BRect rect)
|
||||
{
|
||||
BView::Draw(rect);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MemoryView::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch(message->what) {
|
||||
default:
|
||||
BView::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MemoryView::_Init()
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
}
|
||||
|
||||
|
||||
MemoryView::Listener::~Listener()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2011, Rene Gollent, rene@gollent.com. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef MEMORY_VIEW_H
|
||||
#define MEMORY_VIEW_H
|
||||
|
||||
|
||||
#include <View.h>
|
||||
|
||||
#include "Team.h"
|
||||
|
||||
|
||||
class MemoryView : public BView {
|
||||
public:
|
||||
class Listener;
|
||||
|
||||
public:
|
||||
MemoryView(
|
||||
Team* team, Listener* listener);
|
||||
virtual ~MemoryView();
|
||||
|
||||
static MemoryView* Create(Team* team, Listener* listener);
|
||||
// throws
|
||||
|
||||
void UnsetListener();
|
||||
|
||||
void SetTargetAddress(target_addr_t address);
|
||||
|
||||
void TargetAddressChanged(target_addr_t address);
|
||||
|
||||
virtual void TargetedByScrollView(BScrollView* scrollView);
|
||||
|
||||
virtual void Draw(BRect rect);
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
private:
|
||||
void _Init();
|
||||
|
||||
private:
|
||||
Team* fTeam;
|
||||
target_addr_t fTargetAddress;
|
||||
Listener* fListener;
|
||||
};
|
||||
|
||||
|
||||
class MemoryView::Listener {
|
||||
public:
|
||||
virtual ~Listener();
|
||||
|
||||
virtual void SetTargetAddressRequested(
|
||||
target_addr_t address) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // MEMORY_VIEW_H
|
||||
Reference in New Issue
Block a user