Merge branch 'master' into sam460ex
This commit is contained in:
@@ -29,7 +29,11 @@ if [ IsOptionalHaikuImagePackageAdded OpenSSL ] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if $(HAIKU_GCC_VERSION[1]) >= 4 {
|
if $(HAIKU_GCC_VERSION[1]) >= 4 {
|
||||||
HAIKU_OPENSSL_PACKAGE = openssl-1.0.0j-r1a4-x86-gcc4-2012-08-29.zip ;
|
if $(TARGET_ARCH) = x86_64 {
|
||||||
|
HAIKU_OPENSSL_PACKAGE = openssl-1.0.0j-x86_64-2012-12-18.zip ;
|
||||||
|
} else {
|
||||||
|
HAIKU_OPENSSL_PACKAGE = openssl-1.0.0j-r1a4-x86-gcc4-2012-08-29.zip ;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
HAIKU_OPENSSL_PACKAGE = openssl-1.0.0j-r1a4-x86-gcc2-2012-08-26.zip ;
|
HAIKU_OPENSSL_PACKAGE = openssl-1.0.0j-r1a4-x86-gcc2-2012-08-26.zip ;
|
||||||
}
|
}
|
||||||
@@ -37,9 +41,7 @@ if $(HAIKU_GCC_VERSION[1]) >= 4 {
|
|||||||
HAIKU_OPENSSL_URL = $(baseURL)/$(HAIKU_OPENSSL_PACKAGE) ;
|
HAIKU_OPENSSL_URL = $(baseURL)/$(HAIKU_OPENSSL_PACKAGE) ;
|
||||||
|
|
||||||
if $(HAIKU_BUILD_FEATURE_SSL) {
|
if $(HAIKU_BUILD_FEATURE_SSL) {
|
||||||
if $(TARGET_ARCH) != x86 {
|
if $(TARGET_ARCH) = x86 || $(TARGET_ARCH) = x86_64 {
|
||||||
Echo "SSL build feature not available for $(TARGET_ARCH)" ;
|
|
||||||
} else {
|
|
||||||
# Download the zip archive.
|
# Download the zip archive.
|
||||||
local zipFile = [ DownloadFile $(HAIKU_OPENSSL_PACKAGE)
|
local zipFile = [ DownloadFile $(HAIKU_OPENSSL_PACKAGE)
|
||||||
: $(HAIKU_OPENSSL_URL) ] ;
|
: $(HAIKU_OPENSSL_URL) ] ;
|
||||||
@@ -66,6 +68,8 @@ if $(HAIKU_BUILD_FEATURE_SSL) {
|
|||||||
= [ FDirName $(HAIKU_OPENSSL_DIR) common include ] ;
|
= [ FDirName $(HAIKU_OPENSSL_DIR) common include ] ;
|
||||||
|
|
||||||
EnableBuildFeatures openssl ;
|
EnableBuildFeatures openssl ;
|
||||||
|
} else {
|
||||||
|
Echo "SSL build feature not available for $(TARGET_ARCH)" ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -119,6 +119,13 @@ AddFilesToHaikuImage system : <revisioned>kernel_$(TARGET_ARCH) ;
|
|||||||
AddLibrariesToHaikuHybridImage system lib
|
AddLibrariesToHaikuHybridImage system lib
|
||||||
: $(SYSTEM_LIBS) $(PRIVATE_SYSTEM_LIBS) ;
|
: $(SYSTEM_LIBS) $(PRIVATE_SYSTEM_LIBS) ;
|
||||||
|
|
||||||
|
OPTIONAL_LIBS_ALIASES =
|
||||||
|
libfreetype.so
|
||||||
|
libjpeg.so
|
||||||
|
libpng.so
|
||||||
|
libz.so
|
||||||
|
;
|
||||||
|
|
||||||
# libfreetype.so links to the current freetype lib
|
# libfreetype.so links to the current freetype lib
|
||||||
AddSymlinkToHaikuHybridImage system lib : $(HAIKU_FREETYPE_CURRENT_LIB:BS)
|
AddSymlinkToHaikuHybridImage system lib : $(HAIKU_FREETYPE_CURRENT_LIB:BS)
|
||||||
: $(HAIKU_FREETYPE_CURRENT_LINK) : : true ;
|
: $(HAIKU_FREETYPE_CURRENT_LINK) : : true ;
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ SYSTEM_BIN = [ FFilterByBuildFeatures
|
|||||||
|
|
||||||
SYSTEM_APPS = [ FFilterByBuildFeatures
|
SYSTEM_APPS = [ FFilterByBuildFeatures
|
||||||
AboutSystem ActivityMonitor BootManager@x86 CharacterMap
|
AboutSystem ActivityMonitor BootManager@x86 CharacterMap
|
||||||
CodyCam DeskCalc Devices DiskProbe DiskUsage DriveSetup CDPlayer Expander
|
CodyCam DeskCalc Devices DiskProbe DiskUsage DriveSetup CDPlayer Debugger
|
||||||
GLInfo@x86 Icon-O-Matic Installer LaunchBox Magnify Mail
|
Expander GLInfo@x86 Icon-O-Matic Installer LaunchBox Magnify Mail
|
||||||
MediaConverter MediaPlayer MidiPlayer NetworkStatus PackageInstaller People
|
MediaConverter MediaPlayer MidiPlayer NetworkStatus PackageInstaller People
|
||||||
PoorMan PowerStatus ProcessController Screenshot ShowImage SoundRecorder
|
PoorMan PowerStatus ProcessController Screenshot ShowImage SoundRecorder
|
||||||
StyledEdit Terminal TextSearch TV WebWatch Workspaces
|
StyledEdit Terminal TextSearch TV WebWatch Workspaces
|
||||||
@@ -75,7 +75,7 @@ SYSTEM_LIBS = [ FFilterByBuildFeatures
|
|||||||
PRIVATE_SYSTEM_LIBS = [ FFilterByBuildFeatures
|
PRIVATE_SYSTEM_LIBS = [ FFilterByBuildFeatures
|
||||||
$(HAIKU_JPEG_CURRENT_LIB)
|
$(HAIKU_JPEG_CURRENT_LIB)
|
||||||
$(HAIKU_LIBPNG_CURRENT_LIB)
|
$(HAIKU_LIBPNG_CURRENT_LIB)
|
||||||
$(HAIKU_ZLIB_CURRENT_LIB)
|
$(HAIKU_ZLIB_CURRENT_LIB)
|
||||||
$(HAIKU_FREETYPE_CURRENT_LIB)
|
$(HAIKU_FREETYPE_CURRENT_LIB)
|
||||||
libalm.so
|
libalm.so
|
||||||
libfluidsynth.so
|
libfluidsynth.so
|
||||||
|
|||||||
@@ -643,7 +643,6 @@ if [ IsOptionalHaikuImagePackageAdded DemoPackage_Video ] {
|
|||||||
# Development
|
# Development
|
||||||
if [ IsOptionalHaikuImagePackageAdded Development ] {
|
if [ IsOptionalHaikuImagePackageAdded Development ] {
|
||||||
if $(TARGET_ARCH) = x86 {
|
if $(TARGET_ARCH) = x86 {
|
||||||
AddFilesToHaikuImage system apps : Debugger ;
|
|
||||||
AddSymlinkToHaikuImage home config settings deskbar Applications
|
AddSymlinkToHaikuImage home config settings deskbar Applications
|
||||||
: /boot/system/apps/Debugger : Debugger ;
|
: /boot/system/apps/Debugger : Debugger ;
|
||||||
# autotools
|
# autotools
|
||||||
@@ -1661,16 +1660,11 @@ if [ IsOptionalHaikuImagePackageAdded OpenSSH ] {
|
|||||||
|
|
||||||
# OpenSSL
|
# OpenSSL
|
||||||
if [ IsOptionalHaikuImagePackageAdded OpenSSL ] {
|
if [ IsOptionalHaikuImagePackageAdded OpenSSL ] {
|
||||||
if $(TARGET_ARCH) != x86 {
|
if $(TARGET_ARCH) = x86 || $(TARGET_ARCH) = x86_64 {
|
||||||
Echo "No optional package OpenSSL available for $(TARGET_ARCH)" ;
|
InstallOptionalHaikuImagePackage $(HAIKU_OPENSSL_PACKAGE)
|
||||||
|
: $(HAIKU_OPENSSL_URL) ;
|
||||||
} else {
|
} else {
|
||||||
if $(HAIKU_GCC_VERSION[1]) >= 4 {
|
Echo "No optional package OpenSSL available for $(TARGET_ARCH)" ;
|
||||||
InstallOptionalHaikuImagePackage $(HAIKU_OPENSSL_PACKAGE)
|
|
||||||
: $(HAIKU_OPENSSL_URL) ;
|
|
||||||
} else {
|
|
||||||
InstallOptionalHaikuImagePackage $(HAIKU_OPENSSL_PACKAGE)
|
|
||||||
: $(HAIKU_OPENSSL_URL) ;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,6 @@
|
|||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
class Tokenizer;
|
|
||||||
|
|
||||||
class ParseException {
|
class ParseException {
|
||||||
public:
|
public:
|
||||||
ParseException(const char* message, int32 position)
|
ParseException(const char* message, int32 position)
|
||||||
@@ -35,10 +33,10 @@ class ParseException {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Function;
|
struct Function;
|
||||||
struct Token;
|
|
||||||
class MAPM;
|
class MAPM;
|
||||||
|
|
||||||
class ExpressionParser {
|
class ExpressionParser {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ExpressionParser();
|
ExpressionParser();
|
||||||
~ExpressionParser();
|
~ExpressionParser();
|
||||||
@@ -52,6 +50,10 @@ class ExpressionParser {
|
|||||||
int64 EvaluateToInt64(const char* expressionString);
|
int64 EvaluateToInt64(const char* expressionString);
|
||||||
double EvaluateToDouble(const char* expressionString);
|
double EvaluateToDouble(const char* expressionString);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Token;
|
||||||
|
class Tokenizer;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MAPM _ParseBinary();
|
MAPM _ParseBinary();
|
||||||
MAPM _ParseSum();
|
MAPM _ParseSum();
|
||||||
|
|||||||
@@ -602,7 +602,7 @@ ActivityView::~ActivityView()
|
|||||||
delete fSystemInfoHandler;
|
delete fSystemInfoHandler;
|
||||||
|
|
||||||
// replicant deleted, destroy the about window
|
// replicant deleted, destroy the about window
|
||||||
if (fAboutWindow != NULL)
|
if (fAboutWindow != NULL && fAboutWindow->Lock())
|
||||||
fAboutWindow->Quit();
|
fAboutWindow->Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -193,12 +193,14 @@ Application Debugger :
|
|||||||
CliContext.cpp
|
CliContext.cpp
|
||||||
CliContinueCommand.cpp
|
CliContinueCommand.cpp
|
||||||
CliDebugReportCommand.cpp
|
CliDebugReportCommand.cpp
|
||||||
|
CliDumpMemoryCommand.cpp
|
||||||
|
CliPrintVariableCommand.cpp
|
||||||
|
CliQuitCommand.cpp
|
||||||
CliStackFrameCommand.cpp
|
CliStackFrameCommand.cpp
|
||||||
CliStackTraceCommand.cpp
|
CliStackTraceCommand.cpp
|
||||||
CliStopCommand.cpp
|
CliStopCommand.cpp
|
||||||
CliThreadCommand.cpp
|
CliThreadCommand.cpp
|
||||||
CliThreadsCommand.cpp
|
CliThreadsCommand.cpp
|
||||||
CliQuitCommand.cpp
|
|
||||||
CliVariablesCommand.cpp
|
CliVariablesCommand.cpp
|
||||||
CommandLineUserInterface.cpp
|
CommandLineUserInterface.cpp
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ DebugReportGenerator::DebugReportGenerator(::Team* team,
|
|||||||
fNodeManager(NULL),
|
fNodeManager(NULL),
|
||||||
fListener(listener),
|
fListener(listener),
|
||||||
fWaitingNode(NULL),
|
fWaitingNode(NULL),
|
||||||
|
fCurrentBlock(NULL),
|
||||||
fTraceWaitingThread(NULL)
|
fTraceWaitingThread(NULL)
|
||||||
{
|
{
|
||||||
fTeam->AddListener(this);
|
fTeam->AddListener(this);
|
||||||
@@ -61,6 +62,9 @@ DebugReportGenerator::~DebugReportGenerator()
|
|||||||
fNodeManager->RemoveListener(this);
|
fNodeManager->RemoveListener(this);
|
||||||
fNodeManager->ReleaseReference();
|
fNodeManager->ReleaseReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fCurrentBlock != NULL)
|
||||||
|
fCurrentBlock->ReleaseReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -161,6 +165,19 @@ DebugReportGenerator::ThreadStackTraceChanged(const ::Team::ThreadEvent& event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DebugReportGenerator::MemoryBlockRetrieved(TeamMemoryBlock* block)
|
||||||
|
{
|
||||||
|
if (fCurrentBlock != NULL) {
|
||||||
|
fCurrentBlock->ReleaseReference();
|
||||||
|
fCurrentBlock = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fCurrentBlock = block;
|
||||||
|
release_sem(fTeamDataSem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
DebugReportGenerator::ValueNodeValueChanged(ValueNode* node)
|
DebugReportGenerator::ValueNodeValueChanged(ValueNode* node)
|
||||||
{
|
{
|
||||||
@@ -323,6 +340,9 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output,
|
|||||||
_output << data;
|
_output << data;
|
||||||
if (frame->CountParameters() == 0
|
if (frame->CountParameters() == 0
|
||||||
&& frame->CountLocalVariables() == 0) {
|
&& frame->CountLocalVariables() == 0) {
|
||||||
|
// only dump the topmost frame
|
||||||
|
if (i == 0)
|
||||||
|
_DumpStackFrameMemory(_output, thread->GetCpuState());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,7 +358,7 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output,
|
|||||||
containerLocker.Unlock();
|
containerLocker.Unlock();
|
||||||
_ResolveValueIfNeeded(child->Node(), frame, 1);
|
_ResolveValueIfNeeded(child->Node(), frame, 1);
|
||||||
containerLocker.Lock();
|
containerLocker.Lock();
|
||||||
UiUtils::PrintValueNodeGraph(_output, frame, child, 3, 1);
|
UiUtils::PrintValueNodeGraph(_output, child, 3, 1);
|
||||||
}
|
}
|
||||||
_output << "\n";
|
_output << "\n";
|
||||||
}
|
}
|
||||||
@@ -362,6 +382,24 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DebugReportGenerator::_DumpStackFrameMemory(BString& _output,
|
||||||
|
CpuState* state)
|
||||||
|
{
|
||||||
|
target_addr_t address = state->StackPointer();
|
||||||
|
if (fCurrentBlock == NULL || !fCurrentBlock->Contains(address)) {
|
||||||
|
fListener->InspectRequested(address, this);
|
||||||
|
status_t result = B_OK;
|
||||||
|
do {
|
||||||
|
result = acquire_sem(fTeamDataSem);
|
||||||
|
} while (result == B_INTERRUPTED);
|
||||||
|
}
|
||||||
|
_output << "\t\t\tFrame memory:\n";
|
||||||
|
UiUtils::DumpMemory(_output, 3, fCurrentBlock, address, 1, 16,
|
||||||
|
fCurrentBlock->BaseAddress() + fCurrentBlock->Size() - address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame,
|
DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame,
|
||||||
int32 maxDepth)
|
int32 maxDepth)
|
||||||
@@ -371,7 +409,9 @@ DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame,
|
|||||||
fWaitingNode = node;
|
fWaitingNode = node;
|
||||||
fListener->ValueNodeValueRequested(frame->GetCpuState(),
|
fListener->ValueNodeValueRequested(frame->GetCpuState(),
|
||||||
fNodeManager->GetContainer(), node);
|
fNodeManager->GetContainer(), node);
|
||||||
result = acquire_sem(fTeamDataSem);
|
do {
|
||||||
|
result = acquire_sem(fTeamDataSem);
|
||||||
|
} while (result == B_INTERRUPTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->LocationAndValueResolutionState() == B_OK && maxDepth > 0) {
|
if (node->LocationAndValueResolutionState() == B_OK && maxDepth > 0) {
|
||||||
@@ -380,10 +420,6 @@ DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame,
|
|||||||
for (int32 i = 0; i < node->CountChildren(); i++) {
|
for (int32 i = 0; i < node->CountChildren(); i++) {
|
||||||
ValueNodeChild* child = node->ChildAt(i);
|
ValueNodeChild* child = node->ChildAt(i);
|
||||||
containerLocker.Unlock();
|
containerLocker.Unlock();
|
||||||
result = _ResolveLocationIfNeeded(child, frame);
|
|
||||||
if (result != B_OK)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
result = fNodeManager->AddChildNodes(child);
|
result = fNodeManager->AddChildNodes(child);
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
continue;
|
continue;
|
||||||
@@ -402,18 +438,3 @@ DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame,
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
DebugReportGenerator::_ResolveLocationIfNeeded(ValueNodeChild* child,
|
|
||||||
StackFrame* frame)
|
|
||||||
{
|
|
||||||
ValueLocation* location = NULL;
|
|
||||||
ValueLoader loader(fTeam->GetArchitecture(), fTeam->GetTeamMemory(),
|
|
||||||
fTeam->GetTeamTypeInformation(), frame->GetCpuState());
|
|
||||||
status_t result = child->ResolveLocation(&loader, location);
|
|
||||||
child->SetLocation(location, result);
|
|
||||||
if (location != NULL)
|
|
||||||
location->ReleaseReference();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <Looper.h>
|
#include <Looper.h>
|
||||||
|
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
|
#include "TeamMemoryBlock.h"
|
||||||
#include "ValueNodeContainer.h"
|
#include "ValueNodeContainer.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ class ValueNodeManager;
|
|||||||
|
|
||||||
|
|
||||||
class DebugReportGenerator : public BLooper, private Team::Listener,
|
class DebugReportGenerator : public BLooper, private Team::Listener,
|
||||||
private ValueNodeContainer::Listener {
|
private TeamMemoryBlock::Listener, private ValueNodeContainer::Listener {
|
||||||
public:
|
public:
|
||||||
DebugReportGenerator(::Team* team,
|
DebugReportGenerator(::Team* team,
|
||||||
UserInterfaceListener* listener);
|
UserInterfaceListener* listener);
|
||||||
@@ -39,21 +40,28 @@ public:
|
|||||||
|
|
||||||
virtual void MessageReceived(BMessage* message);
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Team::Listener
|
||||||
virtual void ThreadStackTraceChanged(
|
virtual void ThreadStackTraceChanged(
|
||||||
const Team::ThreadEvent& event);
|
const Team::ThreadEvent& event);
|
||||||
|
|
||||||
|
// TeamMemoryBlock::Listener
|
||||||
|
virtual void MemoryBlockRetrieved(TeamMemoryBlock* block);
|
||||||
|
|
||||||
|
// ValueNodeContainer::Listener
|
||||||
virtual void ValueNodeValueChanged(ValueNode* node);
|
virtual void ValueNodeValueChanged(ValueNode* node);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _GenerateReport(const entry_ref& outputPath);
|
status_t _GenerateReport(const entry_ref& outputPath);
|
||||||
status_t _GenerateReportHeader(BString& output);
|
status_t _GenerateReportHeader(BString& _output);
|
||||||
status_t _DumpLoadedImages(BString& output);
|
status_t _DumpLoadedImages(BString& _output);
|
||||||
status_t _DumpRunningThreads(BString& output);
|
status_t _DumpRunningThreads(BString& _output);
|
||||||
status_t _DumpDebuggedThreadInfo(BString& output,
|
status_t _DumpDebuggedThreadInfo(BString& _output,
|
||||||
::Thread* thread);
|
::Thread* thread);
|
||||||
|
void _DumpStackFrameMemory(BString& _output,
|
||||||
|
CpuState* state);
|
||||||
|
|
||||||
status_t _ResolveLocationIfNeeded(ValueNodeChild* child,
|
|
||||||
StackFrame* frame);
|
|
||||||
status_t _ResolveValueIfNeeded(ValueNode* node,
|
status_t _ResolveValueIfNeeded(ValueNode* node,
|
||||||
StackFrame* frame, int32 maxDepth);
|
StackFrame* frame, int32 maxDepth);
|
||||||
|
|
||||||
@@ -64,6 +72,7 @@ private:
|
|||||||
ValueNodeManager* fNodeManager;
|
ValueNodeManager* fNodeManager;
|
||||||
UserInterfaceListener* fListener;
|
UserInterfaceListener* fListener;
|
||||||
ValueNode* fWaitingNode;
|
ValueNode* fWaitingNode;
|
||||||
|
TeamMemoryBlock* fCurrentBlock;
|
||||||
::Thread* fTraceWaitingThread;
|
::Thread* fTraceWaitingThread;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,10 +26,11 @@ static CliContext* sCurrentContext;
|
|||||||
|
|
||||||
|
|
||||||
struct CliContext::Event : DoublyLinkedListLinkImpl<CliContext::Event> {
|
struct CliContext::Event : DoublyLinkedListLinkImpl<CliContext::Event> {
|
||||||
Event(int type, Thread* thread = NULL)
|
Event(int type, Thread* thread = NULL, TeamMemoryBlock* block = NULL)
|
||||||
:
|
:
|
||||||
fType(type),
|
fType(type),
|
||||||
fThreadReference(thread)
|
fThreadReference(thread),
|
||||||
|
fMemoryBlockReference(block)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,9 +44,15 @@ struct CliContext::Event : DoublyLinkedListLinkImpl<CliContext::Event> {
|
|||||||
return fThreadReference.Get();
|
return fThreadReference.Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TeamMemoryBlock* GetMemoryBlock() const
|
||||||
|
{
|
||||||
|
return fMemoryBlockReference.Get();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int fType;
|
int fType;
|
||||||
BReference<Thread> fThreadReference;
|
BReference<Thread> fThreadReference;
|
||||||
|
BReference<TeamMemoryBlock> fMemoryBlockReference;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -68,7 +75,8 @@ CliContext::CliContext()
|
|||||||
fTerminating(false),
|
fTerminating(false),
|
||||||
fCurrentThread(NULL),
|
fCurrentThread(NULL),
|
||||||
fCurrentStackTrace(NULL),
|
fCurrentStackTrace(NULL),
|
||||||
fCurrentStackFrameIndex(-1)
|
fCurrentStackFrameIndex(-1),
|
||||||
|
fCurrentBlock(NULL)
|
||||||
{
|
{
|
||||||
sCurrentContext = this;
|
sCurrentContext = this;
|
||||||
}
|
}
|
||||||
@@ -118,6 +126,7 @@ CliContext::Init(Team* team, UserInterfaceListener* listener)
|
|||||||
fNodeManager = new(std::nothrow) ValueNodeManager();
|
fNodeManager = new(std::nothrow) ValueNodeManager();
|
||||||
if (fNodeManager == NULL)
|
if (fNodeManager == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
fNodeManager->AddListener(this);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -150,6 +159,11 @@ CliContext::Cleanup()
|
|||||||
fNodeManager->ReleaseReference();
|
fNodeManager->ReleaseReference();
|
||||||
fNodeManager = NULL;
|
fNodeManager = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fCurrentBlock != NULL) {
|
||||||
|
fCurrentBlock->ReleaseReference();
|
||||||
|
fCurrentBlock = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -316,6 +330,25 @@ CliContext::WaitForThreadOrUser()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CliContext::WaitForEvents(int32 eventMask)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
_PrepareToWaitForEvents(eventMask | EVENT_USER_INTERRUPT);
|
||||||
|
uint32 events = fEventsOccurred;
|
||||||
|
if ((events & eventMask) == 0) {
|
||||||
|
events = _WaitForEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((events & EVENT_QUIT) != 0 || (events & eventMask) != 0) {
|
||||||
|
_SignalInputLoop(eventMask);
|
||||||
|
ProcessPendingEvents();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CliContext::ProcessPendingEvents()
|
CliContext::ProcessPendingEvents()
|
||||||
{
|
{
|
||||||
@@ -356,6 +389,13 @@ CliContext::ProcessPendingEvents()
|
|||||||
SetCurrentStackFrameIndex(0);
|
SetCurrentStackFrameIndex(0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case EVENT_TEAM_MEMORY_BLOCK_RETRIEVED:
|
||||||
|
if (fCurrentBlock != NULL) {
|
||||||
|
fCurrentBlock->ReleaseReference();
|
||||||
|
fCurrentBlock = NULL;
|
||||||
|
}
|
||||||
|
fCurrentBlock = event->GetMemoryBlock();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -404,6 +444,45 @@ CliContext::ThreadStackTraceChanged(const Team::ThreadEvent& threadEvent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CliContext::MemoryBlockRetrieved(TeamMemoryBlock* block)
|
||||||
|
{
|
||||||
|
_QueueEvent(
|
||||||
|
new(std::nothrow) Event(EVENT_TEAM_MEMORY_BLOCK_RETRIEVED,
|
||||||
|
NULL, block));
|
||||||
|
_SignalInputLoop(EVENT_TEAM_MEMORY_BLOCK_RETRIEVED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CliContext::ValueNodeChanged(ValueNodeChild* nodeChild, ValueNode* oldNode,
|
||||||
|
ValueNode* newNode)
|
||||||
|
{
|
||||||
|
_SignalInputLoop(EVENT_VALUE_NODE_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CliContext::ValueNodeChildrenCreated(ValueNode* node)
|
||||||
|
{
|
||||||
|
_SignalInputLoop(EVENT_VALUE_NODE_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CliContext::ValueNodeChildrenDeleted(ValueNode* node)
|
||||||
|
{
|
||||||
|
_SignalInputLoop(EVENT_VALUE_NODE_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CliContext::ValueNodeValueChanged(ValueNode* oldNode)
|
||||||
|
{
|
||||||
|
_SignalInputLoop(EVENT_VALUE_NODE_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CliContext::_QueueEvent(Event* event)
|
CliContext::_QueueEvent(Event* event)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,16 +13,21 @@
|
|||||||
#include <Locker.h>
|
#include <Locker.h>
|
||||||
|
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
|
#include "TeamMemoryBlock.h"
|
||||||
|
#include "ValueNodeContainer.h"
|
||||||
|
|
||||||
|
|
||||||
class StackFrame;
|
class StackFrame;
|
||||||
class StackTrace;
|
class StackTrace;
|
||||||
class Team;
|
class Team;
|
||||||
|
class TeamMemoryBlock;
|
||||||
class UserInterfaceListener;
|
class UserInterfaceListener;
|
||||||
class ValueNodeManager;
|
class ValueNodeManager;
|
||||||
|
|
||||||
|
|
||||||
class CliContext : private Team::Listener {
|
class CliContext : private Team::Listener,
|
||||||
|
public TeamMemoryBlock::Listener,
|
||||||
|
private ValueNodeContainer::Listener {
|
||||||
public:
|
public:
|
||||||
enum {
|
enum {
|
||||||
EVENT_QUIT = 0x01,
|
EVENT_QUIT = 0x01,
|
||||||
@@ -30,7 +35,9 @@ public:
|
|||||||
EVENT_THREAD_ADDED = 0x04,
|
EVENT_THREAD_ADDED = 0x04,
|
||||||
EVENT_THREAD_REMOVED = 0x08,
|
EVENT_THREAD_REMOVED = 0x08,
|
||||||
EVENT_THREAD_STOPPED = 0x10,
|
EVENT_THREAD_STOPPED = 0x10,
|
||||||
EVENT_THREAD_STACK_TRACE_CHANGED = 0x20
|
EVENT_THREAD_STACK_TRACE_CHANGED = 0x20,
|
||||||
|
EVENT_VALUE_NODE_CHANGED = 0x40,
|
||||||
|
EVENT_TEAM_MEMORY_BLOCK_RETRIEVED = 0x80
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -64,12 +71,15 @@ public:
|
|||||||
{ return fCurrentStackFrameIndex; }
|
{ return fCurrentStackFrameIndex; }
|
||||||
void SetCurrentStackFrameIndex(int32 index);
|
void SetCurrentStackFrameIndex(int32 index);
|
||||||
|
|
||||||
|
TeamMemoryBlock* CurrentBlock() const { return fCurrentBlock; }
|
||||||
|
|
||||||
const char* PromptUser(const char* prompt);
|
const char* PromptUser(const char* prompt);
|
||||||
void AddLineToInputHistory(const char* line);
|
void AddLineToInputHistory(const char* line);
|
||||||
|
|
||||||
void QuitSession(bool killTeam);
|
void QuitSession(bool killTeam);
|
||||||
|
|
||||||
void WaitForThreadOrUser();
|
void WaitForThreadOrUser();
|
||||||
|
void WaitForEvents(int32 eventMask);
|
||||||
void ProcessPendingEvents();
|
void ProcessPendingEvents();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -87,6 +97,16 @@ private:
|
|||||||
virtual void ThreadStackTraceChanged(
|
virtual void ThreadStackTraceChanged(
|
||||||
const Team::ThreadEvent& event);
|
const Team::ThreadEvent& event);
|
||||||
|
|
||||||
|
// TeamMemoryBlock::Listener
|
||||||
|
virtual void MemoryBlockRetrieved(TeamMemoryBlock* block);
|
||||||
|
|
||||||
|
// ValueNodeContainer::Listener
|
||||||
|
virtual void ValueNodeChanged(ValueNodeChild* nodeChild,
|
||||||
|
ValueNode* oldNode, ValueNode* newNode);
|
||||||
|
virtual void ValueNodeChildrenCreated(ValueNode* node);
|
||||||
|
virtual void ValueNodeChildrenDeleted(ValueNode* node);
|
||||||
|
virtual void ValueNodeValueChanged(ValueNode* node);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _QueueEvent(Event* event);
|
void _QueueEvent(Event* event);
|
||||||
|
|
||||||
@@ -113,6 +133,7 @@ private:
|
|||||||
Thread* fCurrentThread;
|
Thread* fCurrentThread;
|
||||||
StackTrace* fCurrentStackTrace;
|
StackTrace* fCurrentStackTrace;
|
||||||
int32 fCurrentStackFrameIndex;
|
int32 fCurrentStackFrameIndex;
|
||||||
|
TeamMemoryBlock* fCurrentBlock;
|
||||||
|
|
||||||
EventList fPendingEvents;
|
EventList fPendingEvents;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Rene Gollent, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "CliDumpMemoryCommand.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <AutoLocker.h>
|
||||||
|
#include <ExpressionParser.h>
|
||||||
|
|
||||||
|
#include "CliContext.h"
|
||||||
|
#include "Team.h"
|
||||||
|
#include "TeamMemoryBlock.h"
|
||||||
|
#include "UiUtils.h"
|
||||||
|
#include "UserInterface.h"
|
||||||
|
|
||||||
|
|
||||||
|
CliDumpMemoryCommand::CliDumpMemoryCommand()
|
||||||
|
:
|
||||||
|
CliCommand("dump contents of debugged team's memory",
|
||||||
|
"%s [\"]address|expression[\"] [num]\n"
|
||||||
|
"Reads and displays the contents of memory at the target address.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CliDumpMemoryCommand::Execute(int argc, const char* const* argv,
|
||||||
|
CliContext& context)
|
||||||
|
{
|
||||||
|
if (argc < 2) {
|
||||||
|
PrintUsage(argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_addr_t address;
|
||||||
|
ExpressionParser parser;
|
||||||
|
parser.SetSupportHexInput(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
address = parser.EvaluateToInt64(argv[1]);
|
||||||
|
} catch(...) {
|
||||||
|
printf("Error parsing address/expression.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 itemSize = 0;
|
||||||
|
int32 displayWidth = 0;
|
||||||
|
|
||||||
|
// build the format string
|
||||||
|
if (strcmp(argv[0], "db") == 0) {
|
||||||
|
itemSize = 1;
|
||||||
|
displayWidth = 16;
|
||||||
|
} else if (strcmp(argv[0], "ds") == 0) {
|
||||||
|
itemSize = 2;
|
||||||
|
displayWidth = 8;
|
||||||
|
} else if (strcmp(argv[0], "dw") == 0) {
|
||||||
|
itemSize = 4;
|
||||||
|
displayWidth = 4;
|
||||||
|
} else if (strcmp(argv[0], "dl") == 0) {
|
||||||
|
itemSize = 8;
|
||||||
|
displayWidth = 2;
|
||||||
|
} else if (strcmp(argv[0], "string") == 0) {
|
||||||
|
itemSize = 1;
|
||||||
|
displayWidth = -1;
|
||||||
|
} else {
|
||||||
|
printf("dump called in an invalid way!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 num = 0;
|
||||||
|
if (argc == 3) {
|
||||||
|
char *remainder;
|
||||||
|
num = strtol(argv[2], &remainder, 0);
|
||||||
|
if (*remainder != '\0') {
|
||||||
|
printf("Error: invalid parameter \"%s\"\n", argv[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num <= 0)
|
||||||
|
num = displayWidth;
|
||||||
|
|
||||||
|
TeamMemoryBlock* block = context.CurrentBlock();
|
||||||
|
if (block == NULL || !block->Contains(address)) {
|
||||||
|
context.GetUserInterfaceListener()->InspectRequested(address,
|
||||||
|
&context);
|
||||||
|
context.WaitForEvents(CliContext::EVENT_TEAM_MEMORY_BLOCK_RETRIEVED);
|
||||||
|
if (context.IsTerminating())
|
||||||
|
return;
|
||||||
|
block = context.CurrentBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(argv[0], "string")) {
|
||||||
|
printf("%p \"", (char*)address);
|
||||||
|
|
||||||
|
target_addr_t offset = address;
|
||||||
|
char c;
|
||||||
|
while (block->Contains(offset)) {
|
||||||
|
c = *(block->Data() + offset - block->BaseAddress());
|
||||||
|
|
||||||
|
if (c == '\0')
|
||||||
|
break;
|
||||||
|
if (c == '\n')
|
||||||
|
printf("\\n");
|
||||||
|
else if (c == '\t')
|
||||||
|
printf("\\t");
|
||||||
|
else {
|
||||||
|
if (!isprint(c))
|
||||||
|
c = '.';
|
||||||
|
|
||||||
|
printf("%c", c);
|
||||||
|
}
|
||||||
|
++offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\"\n");
|
||||||
|
} else {
|
||||||
|
BString output;
|
||||||
|
UiUtils::DumpMemory(output, 0, block, address, itemSize, displayWidth,
|
||||||
|
num);
|
||||||
|
printf("%s\n", output.String());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Rene Gollent, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef CLI_DUMP_MEMORY_COMMAND_H
|
||||||
|
#define CLI_DUMP_MEMORY_COMMAND_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "CliCommand.h"
|
||||||
|
|
||||||
|
|
||||||
|
class CliDumpMemoryCommand : public CliCommand {
|
||||||
|
public:
|
||||||
|
CliDumpMemoryCommand();
|
||||||
|
virtual void Execute(int argc, const char* const* argv,
|
||||||
|
CliContext& context);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CLI_DUMP_MEMORY_COMMAND_H
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Rene Gollent, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "CliPrintVariableCommand.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
|
#include "CliContext.h"
|
||||||
|
#include "StackFrame.h"
|
||||||
|
#include "StackTrace.h"
|
||||||
|
#include "Team.h"
|
||||||
|
#include "Type.h"
|
||||||
|
#include "UiUtils.h"
|
||||||
|
#include "UserInterface.h"
|
||||||
|
#include "ValueLoader.h"
|
||||||
|
#include "ValueLocation.h"
|
||||||
|
#include "ValueNode.h"
|
||||||
|
#include "ValueNodeContainer.h"
|
||||||
|
#include "ValueNodeManager.h"
|
||||||
|
|
||||||
|
|
||||||
|
CliPrintVariableCommand::CliPrintVariableCommand()
|
||||||
|
:
|
||||||
|
CliCommand("print value(s) of a variable",
|
||||||
|
"%s [--depth n] variable [variable2 ...]\n"
|
||||||
|
"Prints the value and members of the named variable.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CliPrintVariableCommand::Execute(int argc, const char* const* argv,
|
||||||
|
CliContext& context)
|
||||||
|
{
|
||||||
|
if (argc < 2) {
|
||||||
|
PrintUsage(argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueNodeManager* manager = context.GetValueNodeManager();
|
||||||
|
|
||||||
|
ValueNodeContainer* container = manager->GetContainer();
|
||||||
|
AutoLocker<ValueNodeContainer> containerLocker(container);
|
||||||
|
if (container == NULL || container->CountChildren() == 0) {
|
||||||
|
printf("No variables available.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 depth = 1;
|
||||||
|
int32 i = 1;
|
||||||
|
for (; i < argc; i++) {
|
||||||
|
if (strcmp(argv[i], "--depth") == 0) {
|
||||||
|
if (i == argc - 1) {
|
||||||
|
printf("Error: An argument must be supplied for depth.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char* endPointer;
|
||||||
|
depth = strtol(argv[i + 1], &endPointer, 0);
|
||||||
|
if (*endPointer != '\0' || depth < 0) {
|
||||||
|
printf("Error: Invalid parameter \"%s\"\n", argv[i + 1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == argc) {
|
||||||
|
printf("Error: At least one variable name must be supplied.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
while (i < argc) {
|
||||||
|
// TODO: support variable expressions in addition to just names.
|
||||||
|
const char* variableName = argv[i++];
|
||||||
|
for (int32 j = 0; ValueNodeChild* child = container->ChildAt(j); j++) {
|
||||||
|
if (child->Name() == variableName) {
|
||||||
|
found = true;
|
||||||
|
containerLocker.Unlock();
|
||||||
|
_ResolveValueIfNeeded(child->Node(), context, depth);
|
||||||
|
containerLocker.Lock();
|
||||||
|
BString data;
|
||||||
|
UiUtils::PrintValueNodeGraph(data, child, 1, depth);
|
||||||
|
printf("%s", data.String());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
printf("No such variable: %s\n", variableName);
|
||||||
|
found = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
CliPrintVariableCommand::_ResolveValueIfNeeded(ValueNode* node,
|
||||||
|
CliContext& context, int32 maxDepth)
|
||||||
|
{
|
||||||
|
StackFrame* frame = context.GetStackTrace()->FrameAt(
|
||||||
|
context.CurrentStackFrameIndex());
|
||||||
|
if (frame == NULL)
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
|
status_t result = B_OK;
|
||||||
|
ValueNodeManager* manager = context.GetValueNodeManager();
|
||||||
|
ValueNodeContainer* container = manager->GetContainer();
|
||||||
|
AutoLocker<ValueNodeContainer> containerLocker(container);
|
||||||
|
if (node->LocationAndValueResolutionState() == VALUE_NODE_UNRESOLVED) {
|
||||||
|
context.GetUserInterfaceListener()->ValueNodeValueRequested(
|
||||||
|
context.CurrentThread()->GetCpuState(), container, node);
|
||||||
|
|
||||||
|
|
||||||
|
while (node->LocationAndValueResolutionState()
|
||||||
|
== VALUE_NODE_UNRESOLVED) {
|
||||||
|
containerLocker.Unlock();
|
||||||
|
context.WaitForEvents(CliContext::EVENT_VALUE_NODE_CHANGED);
|
||||||
|
containerLocker.Lock();
|
||||||
|
if (context.IsTerminating())
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->LocationAndValueResolutionState() == B_OK && maxDepth > 0) {
|
||||||
|
for (int32 i = 0; i < node->CountChildren(); i++) {
|
||||||
|
ValueNodeChild* child = node->ChildAt(i);
|
||||||
|
containerLocker.Unlock();
|
||||||
|
result = manager->AddChildNodes(child);
|
||||||
|
if (result != B_OK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// since in the case of a pointer to a compound we hide
|
||||||
|
// the intervening compound, don't consider the hidden node
|
||||||
|
// a level for the purposes of depth traversal
|
||||||
|
if (node->GetType()->Kind() == TYPE_ADDRESS
|
||||||
|
&& child->GetType()->Kind() == TYPE_COMPOUND) {
|
||||||
|
_ResolveValueIfNeeded(child->Node(), context, maxDepth);
|
||||||
|
} else
|
||||||
|
_ResolveValueIfNeeded(child->Node(), context, maxDepth - 1);
|
||||||
|
containerLocker.Lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Rene Gollent, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef CLI_PRINT_VARIABLE_COMMAND_H
|
||||||
|
#define CLI_PRINT_VARIABLE_COMMAND_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "CliCommand.h"
|
||||||
|
|
||||||
|
|
||||||
|
class Team;
|
||||||
|
class StackFrame;
|
||||||
|
class ValueNode;
|
||||||
|
class ValueNodeChild;
|
||||||
|
|
||||||
|
|
||||||
|
class CliPrintVariableCommand : public CliCommand {
|
||||||
|
public:
|
||||||
|
CliPrintVariableCommand();
|
||||||
|
virtual void Execute(int argc, const char* const* argv,
|
||||||
|
CliContext& context);
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t _ResolveValueIfNeeded(ValueNode* node,
|
||||||
|
CliContext& context, int32 maxDepth);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CLI_PRINT_VARIABLE_COMMAND_H
|
||||||
@@ -45,11 +45,11 @@ CliStackTraceCommand::Execute(int argc, const char* const* argv,
|
|||||||
|
|
||||||
// get its stack trace
|
// get its stack trace
|
||||||
StackTrace* stackTrace = thread->GetStackTrace();
|
StackTrace* stackTrace = thread->GetStackTrace();
|
||||||
if (stackTrace == NULL) {
|
while (stackTrace == NULL) {
|
||||||
// TODO: Wait for stack trace!
|
context.WaitForEvents(CliContext::EVENT_THREAD_STACK_TRACE_CHANGED);
|
||||||
printf("Current thread doesn't have a stack trace. Waiting not "
|
if (context.IsTerminating())
|
||||||
"implemented yet\n");
|
return;
|
||||||
return;
|
stackTrace = thread->GetStackTrace();
|
||||||
}
|
}
|
||||||
BReference<StackTrace> stackTraceReference(stackTrace);
|
BReference<StackTrace> stackTraceReference(stackTrace);
|
||||||
// hold a reference until we're done
|
// hold a reference until we're done
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#include "CliContext.h"
|
#include "CliContext.h"
|
||||||
#include "CliContinueCommand.h"
|
#include "CliContinueCommand.h"
|
||||||
#include "CliDebugReportCommand.h"
|
#include "CliDebugReportCommand.h"
|
||||||
|
#include "CliDumpMemoryCommand.h"
|
||||||
|
#include "CliPrintVariableCommand.h"
|
||||||
#include "CliQuitCommand.h"
|
#include "CliQuitCommand.h"
|
||||||
#include "CliStackFrameCommand.h"
|
#include "CliStackFrameCommand.h"
|
||||||
#include "CliStackTraceCommand.h"
|
#include "CliStackTraceCommand.h"
|
||||||
@@ -309,10 +311,29 @@ CommandLineUserInterface::_RegisterCommands()
|
|||||||
BReference<CliCommand> stackTraceCommandReference2(
|
BReference<CliCommand> stackTraceCommandReference2(
|
||||||
stackTraceCommandReference.Get());
|
stackTraceCommandReference.Get());
|
||||||
|
|
||||||
|
BReference<CliCommand> dumpCommandReference(
|
||||||
|
new(std::nothrow) CliDumpMemoryCommand, true);
|
||||||
|
BReference<CliCommand> dumpCommandReference2(
|
||||||
|
dumpCommandReference.Get());
|
||||||
|
if (!_RegisterCommand("db", dumpCommandReference.Detach()))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
dumpCommandReference = dumpCommandReference2.Get();
|
||||||
|
if (!_RegisterCommand("ds", dumpCommandReference.Detach()))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
dumpCommandReference = dumpCommandReference2.Get();
|
||||||
|
if (!_RegisterCommand("dw", dumpCommandReference.Detach()))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
dumpCommandReference = dumpCommandReference2.Get();
|
||||||
|
if (!_RegisterCommand("dl", dumpCommandReference.Detach()))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
if (!_RegisterCommand("string", dumpCommandReference2.Detach()))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
if (_RegisterCommand("bt", stackTraceCommandReference.Detach())
|
if (_RegisterCommand("bt", stackTraceCommandReference.Detach())
|
||||||
&& _RegisterCommand("continue", new(std::nothrow) CliContinueCommand)
|
&& _RegisterCommand("continue", new(std::nothrow) CliContinueCommand)
|
||||||
&& _RegisterCommand("frame", new(std::nothrow) CliStackFrameCommand)
|
&& _RegisterCommand("frame", new(std::nothrow) CliStackFrameCommand)
|
||||||
&& _RegisterCommand("help", new(std::nothrow) HelpCommand(this))
|
&& _RegisterCommand("help", new(std::nothrow) HelpCommand(this))
|
||||||
|
&& _RegisterCommand("print", new(std::nothrow) CliPrintVariableCommand)
|
||||||
&& _RegisterCommand("quit", new(std::nothrow) CliQuitCommand)
|
&& _RegisterCommand("quit", new(std::nothrow) CliQuitCommand)
|
||||||
&& _RegisterCommand("save-report",
|
&& _RegisterCommand("save-report",
|
||||||
new(std::nothrow) CliDebugReportCommand)
|
new(std::nothrow) CliDebugReportCommand)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "UiUtils.h"
|
#include "UiUtils.h"
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <DateTime.h>
|
#include <DateTime.h>
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
#include "StackFrame.h"
|
#include "StackFrame.h"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
|
#include "TeamMemoryBlock.h"
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
#include "Type.h"
|
#include "Type.h"
|
||||||
#include "Value.h"
|
#include "Value.h"
|
||||||
@@ -163,8 +165,8 @@ UiUtils::ReportNameForTeam(::Team* team, char* buffer, size_t bufferSize)
|
|||||||
|
|
||||||
|
|
||||||
/*static*/ void
|
/*static*/ void
|
||||||
UiUtils::PrintValueNodeGraph(BString& _output, StackFrame* frame,
|
UiUtils::PrintValueNodeGraph(BString& _output, ValueNodeChild* child,
|
||||||
ValueNodeChild* child, int32 indentLevel, int32 maxDepth)
|
int32 indentLevel, int32 maxDepth)
|
||||||
{
|
{
|
||||||
_output.Append('\t', indentLevel);
|
_output.Append('\t', indentLevel);
|
||||||
_output << child->Name();
|
_output << child->Name();
|
||||||
@@ -215,13 +217,78 @@ UiUtils::PrintValueNodeGraph(BString& _output, StackFrame* frame,
|
|||||||
// level node contains no data of intereest.
|
// level node contains no data of intereest.
|
||||||
if (node->ChildAt(i)->GetType()->Kind() != TYPE_COMPOUND
|
if (node->ChildAt(i)->GetType()->Kind() != TYPE_COMPOUND
|
||||||
|| maxDepth > 1) {
|
|| maxDepth > 1) {
|
||||||
PrintValueNodeGraph(_output, frame, node->ChildAt(i),
|
PrintValueNodeGraph(_output, node->ChildAt(i),
|
||||||
indentLevel + 1, maxDepth - 1);
|
indentLevel + 1, maxDepth - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_output.Append('\t', indentLevel);
|
_output.Append('\t', indentLevel);
|
||||||
_output << "}\n";
|
_output << "}\n";
|
||||||
}
|
} else
|
||||||
|
_output << "\n";
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ void UiUtils::DumpMemory(BString& _output, int32 indentLevel,
|
||||||
|
TeamMemoryBlock* block, target_addr_t address, int32 itemSize,
|
||||||
|
int32 displayWidth, int32 count)
|
||||||
|
{
|
||||||
|
BString data;
|
||||||
|
|
||||||
|
int32 j;
|
||||||
|
_output.Append('\t', indentLevel);
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
uint8* value;
|
||||||
|
|
||||||
|
if ((i % displayWidth) == 0) {
|
||||||
|
int32 displayed = min_c(displayWidth, (count-i)) * itemSize;
|
||||||
|
if (i != 0) {
|
||||||
|
_output.Append("\n");
|
||||||
|
_output.Append('\t', indentLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.SetToFormat("[%#" B_PRIx64 "] ", address + i * itemSize);
|
||||||
|
_output += data;
|
||||||
|
char c;
|
||||||
|
for (j = 0; j < displayed; j++) {
|
||||||
|
if (!block->Contains(address + displayed))
|
||||||
|
break;
|
||||||
|
c = *(block->Data() + address - block->BaseAddress()
|
||||||
|
+ (i * itemSize) + j);
|
||||||
|
if (!isprint(c))
|
||||||
|
c = '.';
|
||||||
|
|
||||||
|
_output += c;
|
||||||
|
}
|
||||||
|
if (count > displayWidth) {
|
||||||
|
// make sure the spacing in the last line is correct
|
||||||
|
for (j = displayed; j < displayWidth * itemSize; j++)
|
||||||
|
_output += ' ';
|
||||||
|
}
|
||||||
|
_output.Append(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
value = block->Data() + address - block->BaseAddress()
|
||||||
|
+ i * itemSize;
|
||||||
|
|
||||||
|
switch (itemSize) {
|
||||||
|
case 1:
|
||||||
|
data.SetToFormat(" %02" B_PRIx8, *(uint8*)value);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
data.SetToFormat(" %04" B_PRIx16, *(uint16*)value);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
data.SetToFormat(" %08" B_PRIx32, *(uint32*)value);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
data.SetToFormat(" %016" B_PRIx64, *(uint64*)value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_output += data;
|
||||||
|
}
|
||||||
|
|
||||||
|
_output.Append("\n");
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,13 +9,17 @@
|
|||||||
|
|
||||||
#include <image.h>
|
#include <image.h>
|
||||||
|
|
||||||
|
#include "Types.h"
|
||||||
|
|
||||||
|
|
||||||
class BString;
|
class BString;
|
||||||
class BVariant;
|
class BVariant;
|
||||||
class StackFrame;
|
class StackFrame;
|
||||||
class Team;
|
class Team;
|
||||||
|
class TeamMemoryBlock;
|
||||||
class ValueNodeChild;
|
class ValueNodeChild;
|
||||||
|
|
||||||
|
|
||||||
class UiUtils {
|
class UiUtils {
|
||||||
public:
|
public:
|
||||||
static const char* ThreadStateToString(int state,
|
static const char* ThreadStateToString(int state,
|
||||||
@@ -34,9 +38,14 @@ public:
|
|||||||
// this function assumes the value nodes have already been resolved
|
// this function assumes the value nodes have already been resolved
|
||||||
// (if possible).
|
// (if possible).
|
||||||
static void PrintValueNodeGraph(BString& _output,
|
static void PrintValueNodeGraph(BString& _output,
|
||||||
StackFrame* frame,
|
|
||||||
ValueNodeChild* child,
|
ValueNodeChild* child,
|
||||||
int32 indentLevel, int32 maxDepth);
|
int32 indentLevel, int32 maxDepth);
|
||||||
|
|
||||||
|
static void DumpMemory(BString& _output,
|
||||||
|
int32 indentLevel,
|
||||||
|
TeamMemoryBlock* block,
|
||||||
|
target_addr_t address, int32 itemSize,
|
||||||
|
int32 displayWidth, int32 count);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ CalcView::~CalcView()
|
|||||||
free(fKeypadDescription);
|
free(fKeypadDescription);
|
||||||
|
|
||||||
// replicant deleted, destroy the about window
|
// replicant deleted, destroy the about window
|
||||||
if (fAboutWindow != NULL)
|
if (fAboutWindow != NULL && fAboutWindow->Lock())
|
||||||
fAboutWindow->Quit();
|
fAboutWindow->Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ NetworkStatusView::NetworkStatusView(BMessage* archive)
|
|||||||
|
|
||||||
NetworkStatusView::~NetworkStatusView()
|
NetworkStatusView::~NetworkStatusView()
|
||||||
{
|
{
|
||||||
if (fAboutWindow != NULL)
|
if (fAboutWindow != NULL && fAboutWindow->Lock())
|
||||||
fAboutWindow->Quit();
|
fAboutWindow->Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ ProcessController::~ProcessController()
|
|||||||
gPCView = NULL;
|
gPCView = NULL;
|
||||||
|
|
||||||
// replicant deleted, destroy the about window
|
// replicant deleted, destroy the about window
|
||||||
if (fAboutWindow != NULL)
|
if (fAboutWindow != NULL && fAboutWindow->Lock())
|
||||||
fAboutWindow->Quit();
|
fAboutWindow->Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ BrowserApp::~BrowserApp()
|
|||||||
delete fCookies;
|
delete fCookies;
|
||||||
delete fCookieJar;
|
delete fCookieJar;
|
||||||
|
|
||||||
if (fAboutWindow != NULL)
|
if (fAboutWindow != NULL && fAboutWindow->Lock())
|
||||||
fAboutWindow->Quit();
|
fAboutWindow->Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -374,7 +374,7 @@ WorkspacesView::WorkspacesView(BMessage* archive)
|
|||||||
|
|
||||||
WorkspacesView::~WorkspacesView()
|
WorkspacesView::~WorkspacesView()
|
||||||
{
|
{
|
||||||
if (fAboutWindow != NULL)
|
if (fAboutWindow != NULL && fAboutWindow->Lock())
|
||||||
fAboutWindow->Quit();
|
fAboutWindow->Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ enum {
|
|||||||
TOKEN_END_OF_LINE
|
TOKEN_END_OF_LINE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Token {
|
struct ExpressionParser::Token {
|
||||||
Token()
|
Token()
|
||||||
: string(""),
|
: string(""),
|
||||||
type(TOKEN_NONE),
|
type(TOKEN_NONE),
|
||||||
@@ -89,7 +89,7 @@ struct Token {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Tokenizer {
|
class ExpressionParser::Tokenizer {
|
||||||
public:
|
public:
|
||||||
Tokenizer()
|
Tokenizer()
|
||||||
: fString(""),
|
: fString(""),
|
||||||
@@ -594,7 +594,7 @@ ExpressionParser::_ParseFunction(const Token& token)
|
|||||||
if (strcmp("e", token.string.String()) == 0)
|
if (strcmp("e", token.string.String()) == 0)
|
||||||
return _ParseFactorial(MAPM(MM_E));
|
return _ParseFactorial(MAPM(MM_E));
|
||||||
else if (strcasecmp("pi", token.string.String()) == 0
|
else if (strcasecmp("pi", token.string.String()) == 0
|
||||||
|| ((unsigned char)token.string.String()[0] == 0xCF
|
|| ((unsigned char)token.string.String()[0] == 0xCF
|
||||||
&& (unsigned char)token.string.String()[1] == 0x80)) {
|
&& (unsigned char)token.string.String()[1] == 0x80)) {
|
||||||
// UTF-8 small greek letter PI
|
// UTF-8 small greek letter PI
|
||||||
return _ParseFactorial(MAPM(MM_PI));
|
return _ParseFactorial(MAPM(MM_PI));
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define HANDOVER_USE_GDB 1
|
//#define HANDOVER_USE_GDB 1
|
||||||
//#define HANDOVER_USE_DEBUGGER 1
|
#define HANDOVER_USE_DEBUGGER 1
|
||||||
|
|
||||||
#undef B_TRANSLATION_CONTEXT
|
#undef B_TRANSLATION_CONTEXT
|
||||||
#define B_TRANSLATION_CONTEXT "DebugServer"
|
#define B_TRANSLATION_CONTEXT "DebugServer"
|
||||||
@@ -555,44 +555,57 @@ TeamDebugHandler::_EnterDebugger(bool saveReport)
|
|||||||
"terminal (debugger) for team %" B_PRId32 "...\n", fTeam));
|
"terminal (debugger) for team %" B_PRId32 "...\n", fTeam));
|
||||||
|
|
||||||
#elif defined(HANDOVER_USE_DEBUGGER)
|
#elif defined(HANDOVER_USE_DEBUGGER)
|
||||||
|
// prepare the argument vector
|
||||||
|
BPath debuggerPath;
|
||||||
if (debugInConsoled) {
|
if (debugInConsoled) {
|
||||||
error = _SetupGDBArguments(arguments, debugInConsoled);
|
error = find_directory(B_SYSTEM_BIN_DIRECTORY, &debuggerPath);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
debug_printf("debug_server: Failed to set up gdb arguments: %s\n",
|
debug_printf("debug_server: can't find system-bin directory: %s\n",
|
||||||
strerror(error));
|
strerror(error));
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
} else {
|
error = debuggerPath.Append("consoled");
|
||||||
// prepare the argument vector
|
|
||||||
BPath debuggerPath;
|
|
||||||
error = find_directory(B_SYSTEM_APPS_DIRECTORY, &debuggerPath);
|
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
debug_printf("debug_server: can't find system-apps directory: %s\n",
|
debug_printf("debug_server: can't append to system-bin path: %s\n",
|
||||||
strerror(error));
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
error = debuggerPath.Append("Debugger");
|
|
||||||
if (error != B_OK) {
|
|
||||||
debug_printf("debug_server: can't append to system-apps path: %s\n",
|
|
||||||
strerror(error));
|
strerror(error));
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!arguments.Add(debuggerPath.Path()))
|
if (!arguments.Add(debuggerPath.Path()))
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
BString debuggerParam;
|
|
||||||
debuggerParam.SetToFormat("%" B_PRId32, fTeam);
|
|
||||||
if (saveReport) {
|
|
||||||
if (!arguments.Add("--save-report"))
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
}
|
|
||||||
if (!arguments.Add("--team") || !arguments.Add(debuggerParam))
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
// start the debugger
|
|
||||||
TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): starting "
|
|
||||||
"graphical debugger for team %" B_PRId32 "...\n", fTeam));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error = find_directory(B_SYSTEM_APPS_DIRECTORY, &debuggerPath);
|
||||||
|
if (error != B_OK) {
|
||||||
|
debug_printf("debug_server: can't find system-apps directory: %s\n",
|
||||||
|
strerror(error));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
error = debuggerPath.Append("Debugger");
|
||||||
|
if (error != B_OK) {
|
||||||
|
debug_printf("debug_server: can't append to system-apps path: %s\n",
|
||||||
|
strerror(error));
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
if (!arguments.Add(debuggerPath.Path()))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
if (debugInConsoled && !arguments.Add("--cli"))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
BString debuggerParam;
|
||||||
|
debuggerParam.SetToFormat("%" B_PRId32, fTeam);
|
||||||
|
if (saveReport) {
|
||||||
|
if (!arguments.Add("--save-report"))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
if (!arguments.Add("--team") || !arguments.Add(debuggerParam))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
// start the debugger
|
||||||
|
TRACE(("debug_server: TeamDebugHandler::_EnterDebugger(): starting "
|
||||||
|
"%s debugger for team %" B_PRId32 "...\n",
|
||||||
|
debugInConsoled ? "command line" : "graphical", fTeam));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int32 i = 0; i < arguments.CountStrings(); i++)
|
for (int32 i = 0; i < arguments.CountStrings(); i++)
|
||||||
|
|||||||
@@ -891,7 +891,7 @@ dump_mutex_info(int argc, char** argv)
|
|||||||
#if KDEBUG
|
#if KDEBUG
|
||||||
kprintf(" holder: %" B_PRId32 "\n", lock->holder);
|
kprintf(" holder: %" B_PRId32 "\n", lock->holder);
|
||||||
#else
|
#else
|
||||||
kprintf(" count: %ld\n", lock->count);
|
kprintf(" count: %" B_PRId32 "\n", lock->count);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
kprintf(" waiting threads:");
|
kprintf(" waiting threads:");
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ dump_sem(struct sem_entry* sem)
|
|||||||
else
|
else
|
||||||
unset_debug_variable("_releaser");
|
unset_debug_variable("_releaser");
|
||||||
#else
|
#else
|
||||||
kprintf("last acquired by: %ld\n", sem->u.used.last_acquirer);
|
kprintf("last acquired by: %" B_PRId32 "\n", sem->u.used.last_acquirer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (sem->u.used.last_acquirer != 0)
|
if (sem->u.used.last_acquirer != 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user