Added the ability to run expressions in any command. Expressions can be

inserted in commands by using backticks:

(lldb) memory read `$rsp-16` `$rsp+16`
(lldb) memory read  -c `(int)strlen(argv[0])` `argv[0]`

The result of the expression will be inserted into the command as a sort of
preprocess stage where this gets done first. We might need to tweak where this
preprocess stage goes, but it is very functional already.

Added ansi color support to the Debugger::FormatPrompt() so you can use things
like "${ansi.fg.blue}" and "${ansi.bold}" many more. This helps in adding 
colors to your prompts without needing to know the ANSI color code strings.

llvm-svn: 141948
This commit is contained in:
Greg Clayton 2011-10-14 07:41:33 +00:00
parent 965de2c197
commit 5a31471e72
7 changed files with 425 additions and 3 deletions

View File

@ -455,6 +455,9 @@ protected:
GetCommandSP (const char *cmd, bool include_aliases = true, bool exact = true, StringList *matches = NULL);
private:
Error
PreprocessCommand (std::string &command);
Debugger &m_debugger; // The debugger session that this interpreter is associated with
ExecutionContext m_exe_ctx; // The current execution context to use when handling commands

View File

@ -0,0 +1,86 @@
//===---------------------AnsiTerminal.h ------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#define ANSI_FG_COLOR_BLACK 30
#define ANSI_FG_COLOR_RED 31
#define ANSI_FG_COLOR_GREEN 32
#define ANSI_FG_COLOR_YELLOW 33
#define ANSI_FG_COLOR_BLUE 34
#define ANSI_FG_COLOR_PURPLE 35
#define ANSI_FG_COLOR_CYAN 36
#define ANSI_FG_COLOR_WHITE 37
#define ANSI_BG_COLOR_BLACK 40
#define ANSI_BG_COLOR_RED 41
#define ANSI_BG_COLOR_GREEN 42
#define ANSI_BG_COLOR_YELLOW 44
#define ANSI_BG_COLOR_BLUE 44
#define ANSI_BG_COLOR_PURPLE 45
#define ANSI_BG_COLOR_CYAN 46
#define ANSI_BG_COLOR_WHITE 47
#define ANSI_SPECIAL_FRAMED 51
#define ANSI_SPECIAL_ENCIRCLED 52
#define ANSI_CTRL_NORMAL 0
#define ANSI_CTRL_BOLD 1
#define ANSI_CTRL_FAINT 2
#define ANSI_CTRL_ITALIC 3
#define ANSI_CTRL_UNDERLINE 4
#define ANSI_CTRL_SLOW_BLINK 5
#define ANSI_CTRL_FAST_BLINK 6
#define ANSI_CTRL_IMAGE_NEGATIVE 7
#define ANSI_CTRL_CONCEAL 8
#define ANSI_CTRL_CROSSED_OUT 9
#define ANSI_ESC_START "\033["
#define ANSI_ESC_END "m"
#define ANSI_1_CTRL(ctrl1) "\033["##ctrl1 ANSI_ESC_END
#define ANSI_2_CTRL(ctrl1,ctrl2) "\033["##ctrl1";"##ctrl2 ANSI_ESC_END
namespace lldb_utility {
namespace ansi {
const char *k_escape_start = "\033[";
const char *k_escape_end = "m";
const char *k_fg_black = "30";
const char *k_fg_red = "31";
const char *k_fg_green = "32";
const char *k_fg_yellow = "33";
const char *k_fg_blue = "34";
const char *k_fg_purple = "35";
const char *k_fg_cyan = "36";
const char *k_fg_white = "37";
const char *k_bg_black = "40";
const char *k_bg_red = "41";
const char *k_bg_green = "42";
const char *k_bg_yellow = "43";
const char *k_bg_blue = "44";
const char *k_bg_purple = "45";
const char *k_bg_cyan = "46";
const char *k_bg_white = "47";
const char *k_ctrl_normal = "0";
const char *k_ctrl_bold = "1";
const char *k_ctrl_faint = "2";
const char *k_ctrl_italic = "3";
const char *k_ctrl_underline = "4";
const char *k_ctrl_slow_blink = "5";
const char *k_ctrl_fast_blink = "6";
const char *k_ctrl_negative = "7";
const char *k_ctrl_conceal = "8";
const char *k_ctrl_crossed_out = "9";
}
}

View File

@ -1,4 +1,4 @@
//===---------------------SharedCluster.h --------------------------*- C++ -*-===//
//===------------------SharedCluster.h --------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//

View File

@ -358,6 +358,7 @@
26BD407F135D2AE000237D80 /* FileLineResolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BD407E135D2ADF00237D80 /* FileLineResolver.cpp */; };
26C72C94124322890068DC16 /* SBStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 26C72C93124322890068DC16 /* SBStream.h */; settings = {ATTRIBUTES = (Public, ); }; };
26C72C961243229A0068DC16 /* SBStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C72C951243229A0068DC16 /* SBStream.cpp */; };
26CF992514428766001E4138 /* AnsiTerminal.h in Headers */ = {isa = PBXBuildFile; fileRef = 26CF992414428766001E4138 /* AnsiTerminal.h */; };
26D265A2136B40EE002EEE45 /* SharingPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 261B5A5311C3F2AD00AABD0A /* SharingPtr.h */; settings = {ATTRIBUTES = (Public, ); }; };
26D265BC136B4269002EEE45 /* lldb-public.h in Headers */ = {isa = PBXBuildFile; fileRef = 26651A14133BEC76005B64B7 /* lldb-public.h */; settings = {ATTRIBUTES = (Public, ); }; };
26D5E15F135BAEA2006EA0A7 /* OptionGroupArchitecture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26D5E15E135BAEA2006EA0A7 /* OptionGroupArchitecture.cpp */; };
@ -1067,6 +1068,7 @@
26C72C951243229A0068DC16 /* SBStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBStream.cpp; path = source/API/SBStream.cpp; sourceTree = "<group>"; };
26C81CA411335651004BDC5A /* UUID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UUID.h; path = include/lldb/Core/UUID.h; sourceTree = "<group>"; };
26C81CA511335651004BDC5A /* UUID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UUID.cpp; path = source/Core/UUID.cpp; sourceTree = "<group>"; };
26CF992414428766001E4138 /* AnsiTerminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AnsiTerminal.h; path = include/lldb/Utility/AnsiTerminal.h; sourceTree = "<group>"; };
26D0DD5010FE554D00271C65 /* BreakpointResolverAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointResolverAddress.h; path = include/lldb/Breakpoint/BreakpointResolverAddress.h; sourceTree = "<group>"; };
26D0DD5110FE554D00271C65 /* BreakpointResolverFileLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointResolverFileLine.h; path = include/lldb/Breakpoint/BreakpointResolverFileLine.h; sourceTree = "<group>"; };
26D0DD5210FE554D00271C65 /* BreakpointResolverName.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointResolverName.h; path = include/lldb/Breakpoint/BreakpointResolverName.h; sourceTree = "<group>"; };
@ -1943,6 +1945,7 @@
2682F168115ED9C800CCFF99 /* Utility */ = {
isa = PBXGroup;
children = (
26CF992414428766001E4138 /* AnsiTerminal.h */,
264723A511FA076E00DE380C /* CleanUp.h */,
94611EAF13CCA363003A22AF /* RefCounter.h */,
94611EB113CCA4A4003A22AF /* RefCounter.cpp */,
@ -2893,6 +2896,7 @@
496B015B1406DEB100F830D5 /* IRInterpreter.h in Headers */,
2682100D143A59AE004BCF2D /* MappedHash.h in Headers */,
2626B6AE143E1BEA00EF935C /* RangeMap.h in Headers */,
26CF992514428766001E4138 /* AnsiTerminal.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -86,7 +86,7 @@
launchStyle = "0"
useCustomWorkingDirectory = "NO"
customWorkingDirectory = "/Volumes/work/gclayton/Documents/devb/attach"
buildConfiguration = "Release"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "YES"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">

View File

@ -31,7 +31,7 @@
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/AnsiTerminal.h"
using namespace lldb;
using namespace lldb_private;
@ -1303,6 +1303,214 @@ Debugger::FormatPrompt
format_addr = *addr;
}
}
else if (::strncmp (var_name_begin, "ansi.", strlen("ansi.")) == 0)
{
var_success = true;
var_name_begin += strlen("ansi."); // Skip the "ansi."
if (::strncmp (var_name_begin, "fg.", strlen("fg.")) == 0)
{
var_name_begin += strlen("fg."); // Skip the "fg."
if (::strncmp (var_name_begin, "black}", strlen("black}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_fg_black,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "red}", strlen("red}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_fg_red,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "green}", strlen("green}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_fg_green,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "yellow}", strlen("yellow}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_fg_yellow,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "blue}", strlen("blue}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_fg_blue,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "purple}", strlen("purple}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_fg_purple,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "cyan}", strlen("cyan}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_fg_cyan,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "white}", strlen("white}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_fg_white,
lldb_utility::ansi::k_escape_end);
}
else
{
var_success = false;
}
}
else if (::strncmp (var_name_begin, "bg.", strlen("bg.")) == 0)
{
var_name_begin += strlen("bg."); // Skip the "bg."
if (::strncmp (var_name_begin, "black}", strlen("black}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_bg_black,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "red}", strlen("red}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_bg_red,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "green}", strlen("green}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_bg_green,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "yellow}", strlen("yellow}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_bg_yellow,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "blue}", strlen("blue}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_bg_blue,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "purple}", strlen("purple}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_bg_purple,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "cyan}", strlen("cyan}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_bg_cyan,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "white}", strlen("white}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_bg_white,
lldb_utility::ansi::k_escape_end);
}
else
{
var_success = false;
}
}
else if (::strncmp (var_name_begin, "normal}", strlen ("normal}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_ctrl_normal,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "bold}", strlen("bold}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_ctrl_bold,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "faint}", strlen("faint}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_ctrl_faint,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "italic}", strlen("italic}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_ctrl_italic,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "underline}", strlen("underline}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_ctrl_underline,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "slow-blink}", strlen("slow-blink}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_ctrl_slow_blink,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "fast-blink}", strlen("fast-blink}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_ctrl_fast_blink,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "negative}", strlen("negative}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_ctrl_negative,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "conceal}", strlen("conceal}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_ctrl_conceal,
lldb_utility::ansi::k_escape_end);
}
else if (::strncmp (var_name_begin, "crossed-out}", strlen("crossed-out}")) == 0)
{
s.Printf ("%s%s%s",
lldb_utility::ansi::k_escape_start,
lldb_utility::ansi::k_ctrl_crossed_out,
lldb_utility::ansi::k_escape_end);
}
else
{
var_success = false;
}
}
break;
case 'p':

View File

@ -947,6 +947,118 @@ CommandInterpreter::BuildAliasResult (const char *alias_name, std::string &raw_i
}
}
Error
CommandInterpreter::PreprocessCommand (std::string &command)
{
// The command preprocessor needs to do things to the command
// line before any parsing of arguments or anything else is done.
// The only current stuff that gets proprocessed is anyting enclosed
// in backtick ('`') characters is evaluated as an expression and
// the result of the expression must be a scalar that can be substituted
// into the command. An example would be:
// (lldb) memory read `$rsp + 20`
Error error; // Error for any expressions that might not evaluate
size_t start_backtick;
size_t pos = 0;
while ((start_backtick = command.find ('`', pos)) != std::string::npos)
{
if (start_backtick > 0 && command[start_backtick-1] == '\\')
{
// The backtick was preceeded by a '\' character, remove the slash
// and don't treat the backtick as the start of an expression
command.erase(start_backtick-1, 1);
// No need to add one to start_backtick since we just deleted a char
pos = start_backtick;
}
else
{
const size_t expr_content_start = start_backtick + 1;
const size_t end_backtick = command.find ('`', expr_content_start);
if (end_backtick == std::string::npos)
return error;
else if (end_backtick == expr_content_start)
{
// Empty expression (two backticks in a row)
command.erase (start_backtick, 2);
}
else
{
std::string expr_str (command, expr_content_start, end_backtick - expr_content_start);
Target *target = m_exe_ctx.GetTargetPtr();
if (target)
{
const bool unwind_on_error = true;
const bool keep_in_memory = false;
ValueObjectSP expr_result_valobj_sp;
ExecutionResults expr_result = target->EvaluateExpression (expr_str.c_str(),
m_exe_ctx.GetFramePtr(),
eExecutionPolicyOnlyWhenNeeded,
unwind_on_error, keep_in_memory,
eNoDynamicValues,
expr_result_valobj_sp);
if (expr_result == eExecutionCompleted)
{
Scalar scalar;
if (expr_result_valobj_sp->ResolveValue (scalar))
{
command.erase (start_backtick, end_backtick - start_backtick + 1);
StreamString value_strm;
const bool show_type = false;
scalar.GetValue (&value_strm, show_type);
size_t value_string_size = value_strm.GetSize();
if (value_string_size)
{
command.insert (start_backtick, value_strm.GetData(), value_string_size);
pos = start_backtick + value_string_size;
continue;
}
else
{
error.SetErrorStringWithFormat("expression value didn't result in a scalar value for the expression '%s'", expr_str.c_str());
}
}
else
{
error.SetErrorStringWithFormat("expression value didn't result in a scalar value for the expression '%s'", expr_str.c_str());
}
}
else
{
if (expr_result_valobj_sp)
error = expr_result_valobj_sp->GetError();
if (error.Success())
{
switch (expr_result)
{
case eExecutionSetupError:
error.SetErrorStringWithFormat("expression setup error for the expression '%s'", expr_str.c_str());
break;
case eExecutionCompleted:
break;
case eExecutionDiscarded:
error.SetErrorStringWithFormat("expression discarded for the expression '%s'", expr_str.c_str());
break;
case eExecutionInterrupted:
error.SetErrorStringWithFormat("expression interrupted for the expression '%s'", expr_str.c_str());
break;
case eExecutionTimedOut:
error.SetErrorStringWithFormat("expression timed out for the expression '%s'", expr_str.c_str());
break;
}
}
}
}
}
if (error.Fail())
break;
}
}
return error;
}
bool
CommandInterpreter::HandleCommand (const char *command_line,
bool add_to_history,
@ -1045,6 +1157,15 @@ CommandInterpreter::HandleCommand (const char *command_line,
return true;
}
Error error (PreprocessCommand (command_string));
if (error.Fail())
{
result.AppendError (error.AsCString());
result.SetStatus(eReturnStatusFailed);
return false;
}
// Phase 1.
// Before we do ANY kind of argument processing, etc. we need to figure out what the real/final command object