Merge branch 'master' into x86_64
This commit is contained in:
commit
284d75bd6a
@ -168,6 +168,12 @@
|
||||
#define DP_LANE_STATUS_CR_DONE_B (1 << 4) // Bool
|
||||
#define DP_LANE_STATUS_CHEQ_DONE_B (1 << 5) // Bool
|
||||
#define DP_LANE_STATUS_SYMB_LOCK_B (1 << 6) // Bool
|
||||
#define DP_LANE_STATUS_EQUALIZED_A DP_LANE_STATUS_CR_DONE_A \
|
||||
|| DP_LANE_STATUS_CHEQ_DONE_A \
|
||||
|| DP_LANE_STATUS_SYMB_LOCK_A
|
||||
#define DP_LANE_STATUS_EQUALIZED_B DP_LANE_STATUS_CR_DONE_B \
|
||||
|| DP_LANE_STATUS_CHEQ_DONE_B \
|
||||
|| DP_LANE_STATUS_SYMB_LOCK_B
|
||||
// DP Lane Align Status (0x0204)
|
||||
#define DP_LANE_ALIGN 0x0204 // Reg
|
||||
#define DP_LANE_ALIGN_DONE (1 << 0) // Bool
|
||||
|
@ -410,6 +410,27 @@ dp_clock_recovery_ok(dp_info* dp)
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
dp_clock_equalization_ok(dp_info* dp)
|
||||
{
|
||||
uint8 laneAlignment
|
||||
= dp->linkStatus[DP_LANE_ALIGN - DP_LANE_STATUS_0_1];
|
||||
|
||||
if ((laneAlignment & DP_LANE_ALIGN_DONE) == 0)
|
||||
return false;
|
||||
|
||||
int lane;
|
||||
for (lane = 0; lane < dp->laneCount; lane++) {
|
||||
uint8 laneStatus = dp_get_lane_status(dp, lane);
|
||||
if ((laneStatus & DP_LANE_STATUS_EQUALIZED_A)
|
||||
!= DP_LANE_STATUS_EQUALIZED_A) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dp_update_vs_emph(uint32 connectorIndex)
|
||||
{
|
||||
@ -612,6 +633,58 @@ dp_link_train_cr(uint32 connectorIndex)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
dp_link_train_ce(uint32 connectorIndex)
|
||||
{
|
||||
TRACE("%s\n", __func__);
|
||||
|
||||
dp_info* dp = &gConnector[connectorIndex]->dpInfo;
|
||||
|
||||
// TODO: DisplayPort: Supports TP3?
|
||||
dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_2);
|
||||
|
||||
dp->trainingAttempts = 0;
|
||||
bool channelEqual = false;
|
||||
|
||||
while (1) {
|
||||
if (dp->trainingReadInterval == 0)
|
||||
snooze(100);
|
||||
else
|
||||
snooze(1000 * 4 * dp->trainingReadInterval);
|
||||
|
||||
if (!dp_get_link_status(dp))
|
||||
break;
|
||||
|
||||
if (dp_clock_equalization_ok(dp)) {
|
||||
channelEqual = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dp->trainingAttempts > 5) {
|
||||
ERROR("%s: ERROR: failed > 5 times!\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
dp_get_adjust_train(dp);
|
||||
|
||||
dp_update_vs_emph(connectorIndex);
|
||||
dp->trainingAttempts++;
|
||||
}
|
||||
|
||||
if (!channelEqual) {
|
||||
ERROR("%s: ERROR: failed\n", __func__);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
TRACE("%s: channels equalized at voltage %d pre-emphasis %d\n",
|
||||
__func__, dp->trainingSet[0] & DP_ADJ_VCC_SWING_LANEA_MASK,
|
||||
(dp->trainingSet[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
|
||||
>> DP_TRAIN_PRE_EMPHASIS_SHIFT);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
dp_link_train(uint8 crtcID, display_mode* mode)
|
||||
{
|
||||
@ -702,7 +775,7 @@ dp_link_train(uint8 crtcID, display_mode* mode)
|
||||
dpcd_reg_write(hwPin, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED);
|
||||
|
||||
dp_link_train_cr(connectorIndex);
|
||||
// TODO: dp_link_train_ce
|
||||
dp_link_train_ce(connectorIndex);
|
||||
|
||||
|
||||
// *** DisplayPort link training finish
|
||||
|
@ -37,6 +37,7 @@ void dp_setup_connectors();
|
||||
|
||||
status_t dp_link_train(uint8 crtcID, display_mode* mode);
|
||||
status_t dp_link_train_cr(uint32 connectorIndex);
|
||||
status_t dp_link_train_ce(uint32 connectorIndex);
|
||||
|
||||
|
||||
#endif /* RADEON_HD_DISPLAYPORT_H */
|
||||
|
@ -174,6 +174,10 @@ Application Debugger :
|
||||
# user_interface/cli
|
||||
CliCommand.cpp
|
||||
CliContext.cpp
|
||||
CliContinueCommand.cpp
|
||||
CliStackTraceCommand.cpp
|
||||
CliStopCommand.cpp
|
||||
CliThreadCommand.cpp
|
||||
CliThreadsCommand.cpp
|
||||
CliQuitCommand.cpp
|
||||
CommandLineUserInterface.cpp
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include "CliCommand.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
CliCommand::CliCommand(const char* summary, const char* usage)
|
||||
:
|
||||
@ -18,3 +20,12 @@ CliCommand::CliCommand(const char* summary, const char* usage)
|
||||
CliCommand::~CliCommand()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliCommand::PrintUsage(const char* commandName) const
|
||||
{
|
||||
printf("Usage: ");
|
||||
printf(Usage(), commandName);
|
||||
printf("\n");
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ public:
|
||||
const char* Summary() const { return fSummary; }
|
||||
const char* Usage() const { return fUsage; }
|
||||
|
||||
void PrintUsage(const char* commandName) const;
|
||||
|
||||
virtual void Execute(int argc, const char* const* argv,
|
||||
CliContext& context) = 0;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "CliContext.h"
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "UserInterface.h"
|
||||
@ -19,6 +20,36 @@
|
||||
static CliContext* sCurrentContext;
|
||||
|
||||
|
||||
// #pragma mark - Event
|
||||
|
||||
|
||||
struct CliContext::Event : DoublyLinkedListLinkImpl<CliContext::Event> {
|
||||
Event(int type, Thread* thread = NULL)
|
||||
:
|
||||
fType(type),
|
||||
fThreadReference(thread)
|
||||
{
|
||||
}
|
||||
|
||||
int Type() const
|
||||
{
|
||||
return fType;
|
||||
}
|
||||
|
||||
Thread* GetThread() const
|
||||
{
|
||||
return fThreadReference.Get();
|
||||
}
|
||||
|
||||
private:
|
||||
int fType;
|
||||
BReference<Thread> fThreadReference;
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark - CliContext
|
||||
|
||||
|
||||
CliContext::CliContext()
|
||||
:
|
||||
fLock("CliContext"),
|
||||
@ -31,7 +62,8 @@ CliContext::CliContext()
|
||||
fInputLoopWaitingForEvents(0),
|
||||
fEventsOccurred(0),
|
||||
fInputLoopWaiting(false),
|
||||
fTerminating(false)
|
||||
fTerminating(false),
|
||||
fCurrentThread(NULL)
|
||||
{
|
||||
sCurrentContext = this;
|
||||
}
|
||||
@ -87,6 +119,9 @@ CliContext::Cleanup()
|
||||
{
|
||||
Terminating();
|
||||
|
||||
while (Event* event = fPendingEvents.RemoveHead())
|
||||
delete event;
|
||||
|
||||
if (fEditLine != NULL) {
|
||||
el_end(fEditLine);
|
||||
fEditLine = NULL;
|
||||
@ -116,6 +151,41 @@ CliContext::Terminating()
|
||||
}
|
||||
|
||||
|
||||
thread_id
|
||||
CliContext::CurrentThreadID() const
|
||||
{
|
||||
return fCurrentThread != NULL ? fCurrentThread->ID() : -1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::SetCurrentThread(Thread* thread)
|
||||
{
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
|
||||
if (fCurrentThread != NULL)
|
||||
fCurrentThread->ReleaseReference();
|
||||
|
||||
fCurrentThread = thread;
|
||||
|
||||
if (fCurrentThread != NULL)
|
||||
fCurrentThread->AcquireReference();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::PrintCurrentThread()
|
||||
{
|
||||
AutoLocker<Team> teamLocker(fTeam);
|
||||
|
||||
if (fCurrentThread != NULL) {
|
||||
printf("current thread: %" B_PRId32 " \"%s\"\n", fCurrentThread->ID(),
|
||||
fCurrentThread->Name());
|
||||
} else
|
||||
printf("no current thread\n");
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
CliContext::PromptUser(const char* prompt)
|
||||
{
|
||||
@ -126,6 +196,8 @@ CliContext::PromptUser(const char* prompt)
|
||||
|
||||
fPrompt = NULL;
|
||||
|
||||
ProcessPendingEvents();
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
@ -155,39 +227,124 @@ CliContext::QuitSession(bool killTeam)
|
||||
void
|
||||
CliContext::WaitForThreadOrUser()
|
||||
{
|
||||
ProcessPendingEvents();
|
||||
|
||||
// TODO: Deal with SIGINT as well!
|
||||
for (;;) {
|
||||
_PrepareToWaitForEvents(
|
||||
EVENT_USER_INTERRUPT | EVENT_THREAD_STATE_CHANGED);
|
||||
EVENT_USER_INTERRUPT | EVENT_THREAD_STOPPED);
|
||||
|
||||
// check whether there are any threads stopped already
|
||||
thread_id stoppedThread = -1;
|
||||
Thread* stoppedThread = NULL;
|
||||
BReference<Thread> stoppedThreadReference;
|
||||
|
||||
AutoLocker<Team> teamLocker(fTeam);
|
||||
|
||||
for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator();
|
||||
Thread* thread = it.Next();) {
|
||||
if (thread->State() == THREAD_STATE_STOPPED) {
|
||||
stoppedThread = thread->ID();
|
||||
stoppedThread = thread;
|
||||
stoppedThreadReference.SetTo(thread);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
teamLocker.Unlock();
|
||||
|
||||
if (stoppedThread >= 0)
|
||||
_SignalInputLoop(EVENT_THREAD_STATE_CHANGED);
|
||||
if (stoppedThread != NULL) {
|
||||
if (fCurrentThread == NULL)
|
||||
fCurrentThread = stoppedThread;
|
||||
|
||||
_SignalInputLoop(EVENT_THREAD_STOPPED);
|
||||
}
|
||||
|
||||
uint32 events = _WaitForEvents();
|
||||
if ((events & EVENT_QUIT) != 0 || stoppedThread >= 0)
|
||||
if ((events & EVENT_QUIT) != 0 || stoppedThread != NULL) {
|
||||
ProcessPendingEvents();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::ThreadStateChanged(const Team::ThreadEvent& event)
|
||||
CliContext::ProcessPendingEvents()
|
||||
{
|
||||
_SignalInputLoop(EVENT_THREAD_STATE_CHANGED);
|
||||
AutoLocker<Team> teamLocker(fTeam);
|
||||
|
||||
for (;;) {
|
||||
// get the next event
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
Event* event = fPendingEvents.RemoveHead();
|
||||
locker.Unlock();
|
||||
if (event == NULL)
|
||||
break;
|
||||
ObjectDeleter<Event> eventDeleter(event);
|
||||
|
||||
// process the event
|
||||
Thread* thread = event->GetThread();
|
||||
|
||||
switch (event->Type()) {
|
||||
case EVENT_QUIT:
|
||||
case EVENT_USER_INTERRUPT:
|
||||
break;
|
||||
case EVENT_THREAD_ADDED:
|
||||
printf("[new thread: %" B_PRId32 " \"%s\"]\n", thread->ID(),
|
||||
thread->Name());
|
||||
break;
|
||||
case EVENT_THREAD_REMOVED:
|
||||
printf("[thread terminated: %" B_PRId32 " \"%s\"]\n",
|
||||
thread->ID(), thread->Name());
|
||||
break;
|
||||
case EVENT_THREAD_STOPPED:
|
||||
printf("[thread stopped: %" B_PRId32 " \"%s\"]\n",
|
||||
thread->ID(), thread->Name());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::ThreadAdded(const Team::ThreadEvent& threadEvent)
|
||||
{
|
||||
_QueueEvent(
|
||||
new(std::nothrow) Event(EVENT_THREAD_ADDED, threadEvent.GetThread()));
|
||||
_SignalInputLoop(EVENT_THREAD_ADDED);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::ThreadRemoved(const Team::ThreadEvent& threadEvent)
|
||||
{
|
||||
_QueueEvent(
|
||||
new(std::nothrow) Event(EVENT_THREAD_REMOVED, threadEvent.GetThread()));
|
||||
_SignalInputLoop(EVENT_THREAD_REMOVED);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::ThreadStateChanged(const Team::ThreadEvent& threadEvent)
|
||||
{
|
||||
if (threadEvent.GetThread()->State() != THREAD_STATE_STOPPED)
|
||||
return;
|
||||
|
||||
_QueueEvent(
|
||||
new(std::nothrow) Event(EVENT_THREAD_STOPPED, threadEvent.GetThread()));
|
||||
_SignalInputLoop(EVENT_THREAD_STOPPED);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContext::_QueueEvent(Event* event)
|
||||
{
|
||||
if (event == NULL) {
|
||||
// no memory -- can't do anything about it
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLocker<BLocker> locker(fLock);
|
||||
fPendingEvents.Add(event);
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,7 +24,9 @@ public:
|
||||
enum {
|
||||
EVENT_QUIT = 0x01,
|
||||
EVENT_USER_INTERRUPT = 0x02,
|
||||
EVENT_THREAD_STATE_CHANGED = 0x04,
|
||||
EVENT_THREAD_ADDED = 0x04,
|
||||
EVENT_THREAD_REMOVED = 0x08,
|
||||
EVENT_THREAD_STOPPED = 0x10,
|
||||
};
|
||||
|
||||
public:
|
||||
@ -37,9 +39,18 @@ public:
|
||||
|
||||
void Terminating();
|
||||
|
||||
bool IsTerminating() const { return fTerminating; }
|
||||
|
||||
// service methods for the input loop thread follow
|
||||
|
||||
Team* GetTeam() const { return fTeam; }
|
||||
UserInterfaceListener* GetUserInterfaceListener() const
|
||||
{ return fListener; }
|
||||
|
||||
Thread* CurrentThread() const { return fCurrentThread; }
|
||||
thread_id CurrentThreadID() const;
|
||||
void SetCurrentThread(Thread* thread);
|
||||
void PrintCurrentThread();
|
||||
|
||||
const char* PromptUser(const char* prompt);
|
||||
void AddLineToInputHistory(const char* line);
|
||||
@ -47,13 +58,24 @@ public:
|
||||
void QuitSession(bool killTeam);
|
||||
|
||||
void WaitForThreadOrUser();
|
||||
void ProcessPendingEvents();
|
||||
|
||||
private:
|
||||
struct Event;
|
||||
|
||||
typedef DoublyLinkedList<Event> EventList;
|
||||
|
||||
private:
|
||||
// Team::Listener
|
||||
virtual void ThreadAdded(const Team::ThreadEvent& event);
|
||||
virtual void ThreadRemoved(const Team::ThreadEvent& event);
|
||||
|
||||
virtual void ThreadStateChanged(
|
||||
const Team::ThreadEvent& event);
|
||||
|
||||
private:
|
||||
void _QueueEvent(Event* event);
|
||||
|
||||
void _PrepareToWaitForEvents(uint32 eventMask);
|
||||
uint32 _WaitForEvents();
|
||||
void _SignalInputLoop(uint32 events);
|
||||
@ -72,6 +94,10 @@ private:
|
||||
uint32 fEventsOccurred;
|
||||
bool fInputLoopWaiting;
|
||||
volatile bool fTerminating;
|
||||
|
||||
Thread* fCurrentThread;
|
||||
|
||||
EventList fPendingEvents;
|
||||
};
|
||||
|
||||
|
||||
|
45
src/apps/debugger/user_interface/cli/CliContinueCommand.cpp
Normal file
45
src/apps/debugger/user_interface/cli/CliContinueCommand.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "CliContinueCommand.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "CliContext.h"
|
||||
#include "MessageCodes.h"
|
||||
#include "Team.h"
|
||||
#include "UserInterface.h"
|
||||
|
||||
CliContinueCommand::CliContinueCommand()
|
||||
:
|
||||
CliCommand("continue the current thread",
|
||||
"%s\n"
|
||||
"Continues the current thread.")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliContinueCommand::Execute(int argc, const char* const* argv,
|
||||
CliContext& context)
|
||||
{
|
||||
AutoLocker<Team> teamLocker(context.GetTeam());
|
||||
Thread* thread = context.CurrentThread();
|
||||
if (thread == NULL) {
|
||||
printf("Error: No current thread.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (thread->State() != THREAD_STATE_STOPPED) {
|
||||
printf("Error: The current thread is not stopped.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
context.GetUserInterfaceListener()->ThreadActionRequested(thread->ID(),
|
||||
MSG_THREAD_RUN);
|
||||
}
|
20
src/apps/debugger/user_interface/cli/CliContinueCommand.h
Normal file
20
src/apps/debugger/user_interface/cli/CliContinueCommand.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef CLI_CONTINUE_COMMAND_H
|
||||
#define CLI_CONTINUE_COMMAND_H
|
||||
|
||||
|
||||
#include "CliCommand.h"
|
||||
|
||||
|
||||
class CliContinueCommand : public CliCommand {
|
||||
public:
|
||||
CliContinueCommand();
|
||||
virtual void Execute(int argc, const char* const* argv,
|
||||
CliContext& context);
|
||||
};
|
||||
|
||||
|
||||
#endif // CLI_CONTINUE_COMMAND_H
|
@ -43,7 +43,7 @@ CliQuitCommand::Execute(int argc, const char* const* argv, CliContext& context)
|
||||
break;
|
||||
}
|
||||
|
||||
if (trimmedLine == "d")
|
||||
if (trimmedLine == "c")
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "CliStackTraceCommand.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "CliContext.h"
|
||||
#include "FunctionInstance.h"
|
||||
#include "StackTrace.h"
|
||||
#include "Team.h"
|
||||
|
||||
|
||||
CliStackTraceCommand::CliStackTraceCommand()
|
||||
:
|
||||
CliCommand("print a stack trace of the current thread",
|
||||
"%s\n"
|
||||
"Prints a stack trace for the current thread.")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliStackTraceCommand::Execute(int argc, const char* const* argv,
|
||||
CliContext& context)
|
||||
{
|
||||
// get the current thread
|
||||
Team* team = context.GetTeam();
|
||||
AutoLocker<Team> teamLocker(team);
|
||||
Thread* thread = context.CurrentThread();
|
||||
if (thread == NULL) {
|
||||
printf("no current thread\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (thread->State() != THREAD_STATE_STOPPED) {
|
||||
printf("Current thread is not stopped. Can't get stack trace.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// get its stack trace
|
||||
StackTrace* stackTrace = thread->GetStackTrace();
|
||||
if (stackTrace == NULL) {
|
||||
// TODO: Wait for stack trace!
|
||||
printf("Current thread doesn't have a stack trace. Waiting not "
|
||||
"implemented yet\n");
|
||||
return;
|
||||
}
|
||||
BReference<StackTrace> stackTraceReference(stackTrace);
|
||||
// hold a reference until we're done
|
||||
|
||||
teamLocker.Unlock();
|
||||
|
||||
// print the stack trace
|
||||
int32 frameCount = stackTrace->CountFrames();
|
||||
for (int32 i = 0; i < frameCount; i++) {
|
||||
StackFrame* frame = stackTrace->FrameAt(i);
|
||||
printf("%3" B_PRId32 " %#" B_PRIx64 " %#" B_PRIx64, i,
|
||||
(uint64)frame->FrameAddress(), (uint64)frame->InstructionPointer());
|
||||
|
||||
Image* image = frame->GetImage();
|
||||
FunctionInstance* function = frame->Function();
|
||||
if (image == NULL && function == NULL) {
|
||||
printf(" ???\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
BString name;
|
||||
target_addr_t baseAddress;
|
||||
if (function != NULL) {
|
||||
name = function->PrettyName();
|
||||
baseAddress = function->Address();
|
||||
} else {
|
||||
name = image->Name();
|
||||
baseAddress = image->Info().TextBase();
|
||||
}
|
||||
|
||||
printf(" %s + %#" B_PRIx64 "\n", name.String(),
|
||||
uint64(frame->InstructionPointer() - baseAddress));
|
||||
}
|
||||
}
|
20
src/apps/debugger/user_interface/cli/CliStackTraceCommand.h
Normal file
20
src/apps/debugger/user_interface/cli/CliStackTraceCommand.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef CLI_STACK_TRACE_COMMAND_H
|
||||
#define CLI_STACK_TRACE_COMMAND_H
|
||||
|
||||
|
||||
#include "CliCommand.h"
|
||||
|
||||
|
||||
class CliStackTraceCommand : public CliCommand {
|
||||
public:
|
||||
CliStackTraceCommand();
|
||||
virtual void Execute(int argc, const char* const* argv,
|
||||
CliContext& context);
|
||||
};
|
||||
|
||||
|
||||
#endif // CLI_STACK_TRACE_COMMAND_H
|
45
src/apps/debugger/user_interface/cli/CliStopCommand.cpp
Normal file
45
src/apps/debugger/user_interface/cli/CliStopCommand.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "CliStopCommand.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "CliContext.h"
|
||||
#include "MessageCodes.h"
|
||||
#include "Team.h"
|
||||
#include "UserInterface.h"
|
||||
|
||||
CliStopCommand::CliStopCommand()
|
||||
:
|
||||
CliCommand("stop the current thread",
|
||||
"%s\n"
|
||||
"Stops the current thread.")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliStopCommand::Execute(int argc, const char* const* argv,
|
||||
CliContext& context)
|
||||
{
|
||||
AutoLocker<Team> teamLocker(context.GetTeam());
|
||||
Thread* thread = context.CurrentThread();
|
||||
if (thread == NULL) {
|
||||
printf("Error: No current thread.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (thread->State() == THREAD_STATE_STOPPED) {
|
||||
printf("Error: The current thread is already stopped.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
context.GetUserInterfaceListener()->ThreadActionRequested(thread->ID(),
|
||||
MSG_THREAD_STOP);
|
||||
}
|
20
src/apps/debugger/user_interface/cli/CliStopCommand.h
Normal file
20
src/apps/debugger/user_interface/cli/CliStopCommand.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef CLI_STOP_COMMAND_H
|
||||
#define CLI_STOP_COMMAND_H
|
||||
|
||||
|
||||
#include "CliCommand.h"
|
||||
|
||||
|
||||
class CliStopCommand : public CliCommand {
|
||||
public:
|
||||
CliStopCommand();
|
||||
virtual void Execute(int argc, const char* const* argv,
|
||||
CliContext& context);
|
||||
};
|
||||
|
||||
|
||||
#endif // CLI_STOP_COMMAND_H
|
58
src/apps/debugger/user_interface/cli/CliThreadCommand.cpp
Normal file
58
src/apps/debugger/user_interface/cli/CliThreadCommand.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "CliThreadCommand.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "CliContext.h"
|
||||
#include "Team.h"
|
||||
|
||||
|
||||
CliThreadCommand::CliThreadCommand()
|
||||
:
|
||||
CliCommand("set or print the current thread",
|
||||
"%s [ <thread ID> ]\n"
|
||||
"Sets the current thread to <thread ID>, if supplied. Otherwise prints "
|
||||
"the\n"
|
||||
"current thread.")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CliThreadCommand::Execute(int argc, const char* const* argv,
|
||||
CliContext& context)
|
||||
{
|
||||
if (argc > 2) {
|
||||
PrintUsage(argv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
// no arguments -- print the current thread
|
||||
context.PrintCurrentThread();
|
||||
return;
|
||||
}
|
||||
|
||||
// parse the argument
|
||||
char* endPointer;
|
||||
long threadID = strtol(argv[1], &endPointer, 0);
|
||||
if (*endPointer != '\0' || threadID < 0) {
|
||||
printf("Error: Invalid parameter \"%s\"\n", argv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// get the thread and change the current thread
|
||||
Team* team = context.GetTeam();
|
||||
AutoLocker<Team> teamLocker(team);
|
||||
if (Thread* thread = team->ThreadByID(threadID))
|
||||
context.SetCurrentThread(thread);
|
||||
else
|
||||
printf("Error: No thread with ID %ld\n", threadID);
|
||||
}
|
20
src/apps/debugger/user_interface/cli/CliThreadCommand.h
Normal file
20
src/apps/debugger/user_interface/cli/CliThreadCommand.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef CLI_THREAD_COMMAND_H
|
||||
#define CLI_THREAD_COMMAND_H
|
||||
|
||||
|
||||
#include "CliCommand.h"
|
||||
|
||||
|
||||
class CliThreadCommand : public CliCommand {
|
||||
public:
|
||||
CliThreadCommand();
|
||||
virtual void Execute(int argc, const char* const* argv,
|
||||
CliContext& context);
|
||||
};
|
||||
|
||||
|
||||
#endif // CLI_THREAD_COMMAND_H
|
@ -16,7 +16,11 @@
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "CliContext.h"
|
||||
#include "CliContinueCommand.h"
|
||||
#include "CliQuitCommand.h"
|
||||
#include "CliStackTraceCommand.h"
|
||||
#include "CliStopCommand.h"
|
||||
#include "CliThreadCommand.h"
|
||||
#include "CliThreadsCommand.h"
|
||||
|
||||
|
||||
@ -56,16 +60,23 @@ private:
|
||||
struct CommandLineUserInterface::HelpCommand : CliCommand {
|
||||
HelpCommand(CommandLineUserInterface* userInterface)
|
||||
:
|
||||
CliCommand("print a list of all commands",
|
||||
"%s\n"
|
||||
"Prints a list of all commands."),
|
||||
CliCommand("print help for a command or a list of all commands",
|
||||
"%s [ <command> ]\n"
|
||||
"Prints help for command <command>, if given, or a list of all "
|
||||
"commands\n"
|
||||
"otherwise."),
|
||||
fUserInterface(userInterface)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Execute(int argc, const char* const* argv, CliContext& context)
|
||||
{
|
||||
fUserInterface->_PrintHelp();
|
||||
if (argc > 2) {
|
||||
PrintUsage(argv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
fUserInterface->_PrintHelp(argc == 2 ? argv[1] : NULL);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -207,9 +218,19 @@ CommandLineUserInterface::_InputLoopEntry(void* data)
|
||||
status_t
|
||||
CommandLineUserInterface::_InputLoop()
|
||||
{
|
||||
thread_id currentThread = -1;
|
||||
|
||||
while (!fTerminating) {
|
||||
// Wait for a thread or Ctrl-C.
|
||||
fContext.WaitForThreadOrUser();
|
||||
if (fContext.IsTerminating())
|
||||
break;
|
||||
|
||||
// Print the active thread, if it changed.
|
||||
if (fContext.CurrentThreadID() != currentThread) {
|
||||
fContext.PrintCurrentThread();
|
||||
currentThread = fContext.CurrentThreadID();
|
||||
}
|
||||
|
||||
// read a command line
|
||||
const char* line = fContext.PromptUser(kDebuggerPrompt);
|
||||
@ -251,8 +272,18 @@ CommandLineUserInterface::_InputLoop()
|
||||
status_t
|
||||
CommandLineUserInterface::_RegisterCommands()
|
||||
{
|
||||
if (_RegisterCommand("help", new(std::nothrow) HelpCommand(this)) &&
|
||||
BReference<CliCommand> stackTraceCommandReference(
|
||||
new(std::nothrow) CliStackTraceCommand, true);
|
||||
BReference<CliCommand> stackTraceCommandReference2(
|
||||
stackTraceCommandReference.Get());
|
||||
|
||||
if (_RegisterCommand("bt", stackTraceCommandReference.Detach()) &&
|
||||
_RegisterCommand("continue", new(std::nothrow) CliContinueCommand) &&
|
||||
_RegisterCommand("help", new(std::nothrow) HelpCommand(this)) &&
|
||||
_RegisterCommand("quit", new(std::nothrow) CliQuitCommand) &&
|
||||
_RegisterCommand("sc", stackTraceCommandReference2.Detach()) &&
|
||||
_RegisterCommand("stop", new(std::nothrow) CliStopCommand) &&
|
||||
_RegisterCommand("thread", new(std::nothrow) CliThreadCommand) &&
|
||||
_RegisterCommand("threads", new(std::nothrow) CliThreadsCommand)) {
|
||||
return B_OK;
|
||||
}
|
||||
@ -282,33 +313,63 @@ CommandLineUserInterface::_RegisterCommand(const BString& name,
|
||||
void
|
||||
CommandLineUserInterface::_ExecuteCommand(int argc, const char* const* argv)
|
||||
{
|
||||
const char* commandName = argv[0];
|
||||
CommandEntry* commandEntry = _FindCommand(argv[0]);
|
||||
if (commandEntry != NULL)
|
||||
commandEntry->Command()->Execute(argc, argv, fContext);
|
||||
}
|
||||
|
||||
|
||||
CommandLineUserInterface::CommandEntry*
|
||||
CommandLineUserInterface::_FindCommand(const char* commandName)
|
||||
{
|
||||
size_t commandNameLength = strlen(commandName);
|
||||
|
||||
CommandEntry* firstEntry = NULL;
|
||||
// try to find an exact match first
|
||||
CommandEntry* commandEntry = NULL;
|
||||
for (int32 i = 0; CommandEntry* entry = fCommands.ItemAt(i); i++) {
|
||||
if (entry->Name() == commandName) {
|
||||
commandEntry = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing found yet, try partial matches, but only, if they are
|
||||
// unambiguous.
|
||||
if (commandEntry == NULL) {
|
||||
for (int32 i = 0; CommandEntry* entry = fCommands.ItemAt(i); i++) {
|
||||
if (entry->Name().Compare(commandName, commandNameLength) == 0) {
|
||||
if (firstEntry != NULL) {
|
||||
printf("Ambiguous command \"%s\".\n", commandName);
|
||||
return;
|
||||
if (commandEntry != NULL) {
|
||||
printf("Error: Ambiguous command \"%s\".\n", commandName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
firstEntry = entry;
|
||||
commandEntry = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (firstEntry == NULL) {
|
||||
printf("Unknown command \"%s\".\n", commandName);
|
||||
return;
|
||||
if (commandEntry == NULL) {
|
||||
printf("Error: Unknown command \"%s\".\n", commandName);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
firstEntry->Command()->Execute(argc, argv, fContext);
|
||||
return commandEntry;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CommandLineUserInterface::_PrintHelp()
|
||||
CommandLineUserInterface::_PrintHelp(const char* commandName)
|
||||
{
|
||||
// If a command name is given, print the usage for that one.
|
||||
if (commandName != NULL) {
|
||||
CommandEntry* commandEntry = _FindCommand(commandName);
|
||||
if (commandEntry != NULL)
|
||||
commandEntry->Command()->PrintUsage(commandEntry->Name().String());
|
||||
return;
|
||||
}
|
||||
|
||||
// No command name given -- print a list of all commands.
|
||||
|
||||
// determine longest command name
|
||||
int32 longestCommandName = 0;
|
||||
for (int32 i = 0; CommandEntry* entry = fCommands.ItemAt(i); i++) {
|
||||
|
@ -64,7 +64,8 @@ private:
|
||||
CliCommand* command);
|
||||
void _ExecuteCommand(int argc,
|
||||
const char* const* argv);
|
||||
void _PrintHelp();
|
||||
CommandEntry* _FindCommand(const char* commandName);
|
||||
void _PrintHelp(const char* commandName);
|
||||
|
||||
private:
|
||||
CliContext fContext;
|
||||
|
Loading…
Reference in New Issue
Block a user