forked from OSchip/llvm-project
Added a way to open the current source file & line in an external editor, and you can turn this on with:
lldb -e llvm-svn: 112502
This commit is contained in:
parent
9026d4b488
commit
e40e42181f
|
@ -106,6 +106,14 @@ public:
|
|||
|
||||
lldb::SBSourceManager &
|
||||
GetSourceManager ();
|
||||
|
||||
// FIXME: Once we get the set show stuff in place, the driver won't need
|
||||
// an interface to the Set/Get UseExternalEditor.
|
||||
bool
|
||||
SetUseExternalEditor (bool input);
|
||||
|
||||
bool
|
||||
UseExternalEditor ();
|
||||
|
||||
bool
|
||||
GetDefaultArchitecture (char *arch_name, size_t arch_name_len);
|
||||
|
|
|
@ -143,6 +143,20 @@ public:
|
|||
|
||||
static lldb::DebuggerSP
|
||||
FindDebuggerWithID (lldb::user_id_t id);
|
||||
|
||||
bool
|
||||
SetUseExternalEditor (bool value)
|
||||
{
|
||||
bool old_value = m_use_external_editor;
|
||||
m_use_external_editor = value;
|
||||
return old_value;
|
||||
}
|
||||
|
||||
bool
|
||||
UseExternalEditor ()
|
||||
{
|
||||
return m_use_external_editor;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -170,6 +184,7 @@ protected:
|
|||
|
||||
std::stack<lldb::InputReaderSP> m_input_readers;
|
||||
std::string m_input_reader_data;
|
||||
bool m_use_external_editor; // FIXME: Convert this to a set/show variable on the debugger.
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -267,6 +267,9 @@ public:
|
|||
|
||||
static ArchSpec
|
||||
GetArchSpecForExistingProcess (const char *process_name);
|
||||
|
||||
static bool
|
||||
OpenFileInExternalEditor (FileSpec &file_spec, uint32_t line_no);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -356,6 +356,7 @@
|
|||
4C08CDEC11C81F1E001610A8 /* ThreadSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C08CDEB11C81F1E001610A8 /* ThreadSpec.h */; };
|
||||
4C5DBBC811E3FEC60035160F /* CommandObjectCommands.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C5DBBC611E3FEC60035160F /* CommandObjectCommands.cpp */; };
|
||||
4C5DBBC911E3FEC60035160F /* CommandObjectCommands.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C5DBBC711E3FEC60035160F /* CommandObjectCommands.h */; };
|
||||
4C74CB6312288704006A8171 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C74CB6212288704006A8171 /* Carbon.framework */; };
|
||||
4CA9637B11B6E99A00780E28 /* CommandObjectApropos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CA9637911B6E99A00780E28 /* CommandObjectApropos.cpp */; };
|
||||
9A19A6AF1163BBB200E0D453 /* SBValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A19A6A51163BB7E00E0D453 /* SBValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
9A19A6B01163BBB300E0D453 /* SBValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */; };
|
||||
|
@ -960,6 +961,7 @@
|
|||
4C51FF1611A4C486007C962F /* ObjCTrampolineHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjCTrampolineHandler.cpp; sourceTree = "<group>"; };
|
||||
4C5DBBC611E3FEC60035160F /* CommandObjectCommands.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectCommands.cpp; path = source/Commands/CommandObjectCommands.cpp; sourceTree = "<group>"; };
|
||||
4C5DBBC711E3FEC60035160F /* CommandObjectCommands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectCommands.h; path = source/Commands/CommandObjectCommands.h; sourceTree = "<group>"; };
|
||||
4C74CB6212288704006A8171 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
|
||||
4C98D3DA118FB96F00E575D0 /* ClangFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangFunction.cpp; path = source/Expression/ClangFunction.cpp; sourceTree = "<group>"; };
|
||||
4C98D3DB118FB96F00E575D0 /* RecordingMemoryManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RecordingMemoryManager.cpp; path = source/Expression/RecordingMemoryManager.cpp; sourceTree = "<group>"; };
|
||||
4C98D3E0118FB98F00E575D0 /* ClangFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangFunction.h; path = include/lldb/Expression/ClangFunction.h; sourceTree = "<group>"; };
|
||||
|
@ -1075,6 +1077,7 @@
|
|||
26680231115FD1A0008E1FE4 /* Foundation.framework in Frameworks */,
|
||||
26680232115FD1A4008E1FE4 /* libpython2.6.dylib in Frameworks */,
|
||||
26680233115FD1A7008E1FE4 /* libobjc.dylib in Frameworks */,
|
||||
4C74CB6312288704006A8171 /* Carbon.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -1105,6 +1108,7 @@
|
|||
08FB7795FE84155DC02AAC07 /* Source */,
|
||||
26F5C22410F3D950009D5894 /* Tools */,
|
||||
1AB674ADFE9D54B511CA2CBB /* Products */,
|
||||
4C74CB6212288704006A8171 /* Carbon.framework */,
|
||||
);
|
||||
name = lldb;
|
||||
sourceTree = "<group>";
|
||||
|
|
|
@ -563,3 +563,23 @@ SBDebugger::FindDebuggerWithID (int id)
|
|||
sb_debugger.reset (debugger_sp);
|
||||
return sb_debugger;
|
||||
}
|
||||
|
||||
bool
|
||||
SBDebugger::SetUseExternalEditor (bool value)
|
||||
{
|
||||
if (m_opaque_sp)
|
||||
return m_opaque_sp->SetUseExternalEditor (value);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
SBDebugger::UseExternalEditor ()
|
||||
{
|
||||
if (m_opaque_sp)
|
||||
return m_opaque_sp->UseExternalEditor ();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -114,12 +114,19 @@ public:
|
|||
|
||||
if (exe_ctx.frame)
|
||||
{
|
||||
bool already_shown = false;
|
||||
SymbolContext frame_sc(exe_ctx.frame->GetSymbolContext(eSymbolContextLineEntry));
|
||||
if (interpreter.GetDebugger().UseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0)
|
||||
{
|
||||
already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line);
|
||||
}
|
||||
|
||||
if (DisplayFrameForExecutionContext (exe_ctx.thread,
|
||||
exe_ctx.frame,
|
||||
interpreter,
|
||||
result.GetOutputStream(),
|
||||
true,
|
||||
true,
|
||||
!already_shown,
|
||||
3,
|
||||
3))
|
||||
{
|
||||
|
|
|
@ -60,13 +60,21 @@ lldb_private::DisplayThreadInfo
|
|||
// Show one frame with only the first showing source
|
||||
if (show_source)
|
||||
{
|
||||
bool already_shown = false;
|
||||
StackFrameSP frame_sp = thread->GetStackFrameAtIndex(0);
|
||||
SymbolContext frame_sc(frame_sp->GetSymbolContext (eSymbolContextLineEntry));
|
||||
if (interpreter.GetDebugger().UseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0)
|
||||
{
|
||||
already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line);
|
||||
}
|
||||
|
||||
DisplayFramesForExecutionContext (thread,
|
||||
interpreter,
|
||||
strm,
|
||||
0, // Start at first frame
|
||||
1, // Number of frames to show
|
||||
false,// Don't show the frame info since we already displayed most of it above...
|
||||
1, // Show source for the first frame
|
||||
!already_shown, // Show source for the first frame
|
||||
3, // lines of source context before
|
||||
3); // lines of source context after
|
||||
}
|
||||
|
|
|
@ -128,7 +128,8 @@ Debugger::Debugger () :
|
|||
m_command_interpreter_ap (new CommandInterpreter (*this, eScriptLanguageDefault, false)),
|
||||
m_exe_ctx (),
|
||||
m_input_readers (),
|
||||
m_input_reader_data ()
|
||||
m_input_reader_data (),
|
||||
m_use_external_editor(false)
|
||||
{
|
||||
m_command_interpreter_ap->Initialize ();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <objc/objc-auto.h>
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
#include "cfcpp/CFCBundle.h"
|
||||
#include "cfcpp/CFCReleaser.h"
|
||||
|
@ -779,3 +781,116 @@ Host::GetArchSpecForExistingProcess (const char *process_name)
|
|||
}
|
||||
return returnSpec;
|
||||
}
|
||||
|
||||
bool
|
||||
Host::OpenFileInExternalEditor (FileSpec &file_spec, uint32_t line_no)
|
||||
{
|
||||
// We attach this to an 'odoc' event to specify a particular selection
|
||||
typedef struct {
|
||||
int16_t reserved0; // must be zero
|
||||
int16_t fLineNumber;
|
||||
int32_t fSelStart;
|
||||
int32_t fSelEnd;
|
||||
uint32_t reserved1; // must be zero
|
||||
uint32_t reserved2; // must be zero
|
||||
} BabelAESelInfo;
|
||||
|
||||
char file_path[PATH_MAX];
|
||||
file_spec.GetPath(file_path, PATH_MAX);
|
||||
CFCString file_cfstr (file_path, kCFStringEncodingUTF8);
|
||||
CFCReleaser<CFURLRef> file_URL(::CFURLCreateWithFileSystemPath(NULL, file_cfstr.get(), kCFURLPOSIXPathStyle, false));
|
||||
|
||||
OSStatus error;
|
||||
BabelAESelInfo file_and_line_info;
|
||||
|
||||
AEKeyDesc file_and_line_desc;
|
||||
|
||||
bzero(&file_and_line_info, sizeof (file_and_line_info));
|
||||
file_and_line_info.fSelStart = 1;
|
||||
file_and_line_info.fSelEnd = 1;
|
||||
file_and_line_info.fLineNumber = line_no - 1;
|
||||
|
||||
error = AECreateDesc(typeChar, &file_and_line_info, sizeof (file_and_line_info), &(file_and_line_desc.descContent));
|
||||
if (error != noErr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
file_and_line_desc.descKey = keyAEPosition;
|
||||
|
||||
LSApplicationParameters app_params;
|
||||
bzero (&app_params, sizeof (app_params));
|
||||
app_params.flags = kLSLaunchDefaults | kLSLaunchDontSwitch;
|
||||
|
||||
ProcessSerialNumber psn;
|
||||
CFCReleaser<CFArrayRef> file_array(CFArrayCreate (NULL, (const void **) file_URL.ptr_address(false), 1, NULL));
|
||||
error = LSOpenURLsWithRole(file_array.get(), kLSRolesAll, &file_and_line_desc, &app_params, &psn, 1);
|
||||
|
||||
AEDisposeDesc (&(file_and_line_desc.descContent));
|
||||
|
||||
if (error != noErr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ProcessInfoRec which_process;
|
||||
bzero(&which_process, sizeof(which_process));
|
||||
unsigned char ap_name[PATH_MAX];
|
||||
which_process.processName = ap_name;
|
||||
error = GetProcessInformation (&psn, &which_process);
|
||||
|
||||
bool using_xcode = strncmp((char *) ap_name+1, "Xcode", 5) == 0;
|
||||
|
||||
// Xcode doesn't obey the line number in the Open Apple Event. So I have to send
|
||||
// it an AppleScript to focus on the right line.
|
||||
|
||||
if (using_xcode)
|
||||
{
|
||||
static ComponentInstance osa_component = NULL;
|
||||
static const char *as_template = "tell application \"Xcode\"\n"
|
||||
"set doc to the first document whose path is \"%s\"\n"
|
||||
"set the selection to paragraph %d of doc\n"
|
||||
"--- set the selected paragraph range to {%d, %d} of doc\n"
|
||||
"end tell\n";
|
||||
const int chars_for_int = 32;
|
||||
static int as_template_len = strlen (as_template);
|
||||
|
||||
|
||||
char *as_str;
|
||||
AEDesc as_desc;
|
||||
|
||||
if (osa_component == NULL)
|
||||
{
|
||||
osa_component = OpenDefaultComponent (kOSAComponentType,
|
||||
kAppleScriptSubtype);
|
||||
}
|
||||
|
||||
if (osa_component == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t as_str_size = as_template_len + strlen (file_path) + 3 * chars_for_int + 1;
|
||||
as_str = (char *) malloc (as_str_size);
|
||||
snprintf (as_str, as_str_size - 1, as_template, file_path, line_no, line_no, line_no);
|
||||
error = AECreateDesc (typeChar, as_str, strlen (as_str), &as_desc);
|
||||
|
||||
free (as_str);
|
||||
|
||||
if (error != noErr)
|
||||
return false;
|
||||
|
||||
OSAID ret_OSAID;
|
||||
error = OSACompileExecute (osa_component, &as_desc, kOSANullScript,
|
||||
kOSAModeNeverInteract, &ret_OSAID);
|
||||
|
||||
OSADispose (osa_component, ret_OSAID);
|
||||
|
||||
AEDisposeDesc (&as_desc);
|
||||
|
||||
if (error != noErr)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -96,11 +96,14 @@ public:
|
|||
// assertion fires, check the offending code, or call
|
||||
// reset() prior to using the "ptr_address()" member to make
|
||||
// sure any owned objects has CFRelease called on it.
|
||||
// I had to add the "enforce_null" bool here because some
|
||||
// API's require the pointer address even though they don't change it.
|
||||
//----------------------------------------------------------
|
||||
T*
|
||||
ptr_address()
|
||||
ptr_address(bool enforce_null = true)
|
||||
{
|
||||
assert (_ptr == NULL);
|
||||
if (enforce_null)
|
||||
assert (_ptr == NULL);
|
||||
return &_ptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,9 @@ static lldb::OptionDefinition g_options[] =
|
|||
{ LLDB_OPT_SET_3, true, "file", 'f', required_argument, NULL, NULL, "<filename>",
|
||||
"Tells the debugger to use the file <filename> as the program to be debugged." },
|
||||
|
||||
{ LLDB_OPT_SET_ALL, false, "editor", 'e', no_argument, NULL, NULL, "<external-editor>",
|
||||
"Tells the debugger to open source files using the host's \"external editor\" mechanism." },
|
||||
|
||||
// { LLDB_OPT_SET_4, true, "crash-log", 'c', required_argument, NULL, NULL, "<file>",
|
||||
// "Load executable images from a crash log for symbolication." },
|
||||
|
||||
|
@ -324,7 +327,8 @@ Driver::OptionData::OptionData () :
|
|||
m_debug_mode (false),
|
||||
m_print_version (false),
|
||||
m_print_help (false),
|
||||
m_seen_options()
|
||||
m_seen_options(),
|
||||
m_use_external_editor(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -341,6 +345,7 @@ Driver::OptionData::Clear ()
|
|||
m_debug_mode = false;
|
||||
m_print_help = false;
|
||||
m_print_version = false;
|
||||
m_use_external_editor = false;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -508,7 +513,10 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exit)
|
|||
case 'c':
|
||||
m_option_data.m_crash_log = optarg;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
m_option_data.m_use_external_editor = true;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
{
|
||||
SBFileSpec file(optarg);
|
||||
|
@ -1042,6 +1050,8 @@ Driver::MainLoop ()
|
|||
m_debugger.SetErrorFileHandle (stderr, false);
|
||||
m_debugger.SetOutputFileHandle (stdout, false);
|
||||
m_debugger.SetInputFileHandle (stdin, true);
|
||||
|
||||
m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
|
||||
|
||||
// You have to drain anything that comes to the master side of the PTY. master_out_comm is
|
||||
// for that purpose. The reason you need to do this is a curious reason... editline will echo
|
||||
|
|
|
@ -103,6 +103,7 @@ public:
|
|||
bool m_debug_mode;
|
||||
bool m_print_version;
|
||||
bool m_print_help;
|
||||
bool m_use_external_editor; // FIXME: When we have set/show variables we can remove this from here.
|
||||
typedef std::set<char> OptionSet;
|
||||
OptionSet m_seen_options;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue