2010-06-09 00:52:24 +08:00
//===-- CommandObjectSource.cpp ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "CommandObjectSource.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
2010-06-16 03:49:27 +08:00
# include "lldb/Interpreter/Args.h"
2010-06-23 09:19:29 +08:00
# include "lldb/Core/Debugger.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/CommandReturnObject.h"
2010-07-07 11:36:20 +08:00
# include "lldb/Core/FileSpec.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Target/Process.h"
2010-07-07 11:36:20 +08:00
# include "lldb/Core/SourceManager.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Target/TargetList.h"
2010-07-07 11:36:20 +08:00
# include "lldb/Interpreter/CommandCompletions.h"
# include "lldb/Interpreter/Options.h"
2010-06-09 00:52:24 +08:00
using namespace lldb ;
using namespace lldb_private ;
//-------------------------------------------------------------------------
2010-07-07 11:36:20 +08:00
// CommandObjectSourceList
2010-06-09 00:52:24 +08:00
//-------------------------------------------------------------------------
2010-07-07 11:36:20 +08:00
class CommandObjectSourceInfo : public CommandObject
2010-06-09 00:52:24 +08:00
{
2010-07-07 11:36:20 +08:00
class CommandOptions : public Options
{
public :
CommandOptions ( ) :
Options ( )
{
}
~ CommandOptions ( )
{
}
Error
SetOptionValue ( int option_idx , const char * option_arg )
{
Error error ;
const char short_option = g_option_table [ option_idx ] . short_option ;
switch ( short_option )
{
case ' l ' :
start_line = Args : : StringToUInt32 ( option_arg , 0 ) ;
if ( start_line = = 0 )
error . SetErrorStringWithFormat ( " Invalid line number: '%s'. \n " , option_arg ) ;
break ;
case ' f ' :
file_name = option_arg ;
break ;
default :
error . SetErrorStringWithFormat ( " Unrecognized short option '%c'. \n " , short_option ) ;
break ;
}
return error ;
}
void
ResetOptionValues ( )
{
Options : : ResetOptionValues ( ) ;
file_spec . Clear ( ) ;
file_name . clear ( ) ;
start_line = 0 ;
}
const lldb : : OptionDefinition *
GetDefinitions ( )
{
return g_option_table ;
}
static lldb : : OptionDefinition g_option_table [ ] ;
// Instance variables to hold the values for command options.
FileSpec file_spec ;
std : : string file_name ;
uint32_t start_line ;
} ;
public :
CommandObjectSourceInfo ( ) :
CommandObject ( " source info " ,
" Display info on the source lines from the current executable's debug info. " ,
" source info [<cmd-options>] " )
{
}
~ CommandObjectSourceInfo ( )
{
}
Options *
GetOptions ( )
{
return & m_options ;
}
bool
Execute
(
CommandInterpreter & interpreter ,
Args & args ,
CommandReturnObject & result
)
{
result . AppendError ( " Not yet implemented " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
protected :
CommandOptions m_options ;
} ;
lldb : : OptionDefinition
CommandObjectSourceInfo : : CommandOptions : : g_option_table [ ] =
2010-06-09 00:52:24 +08:00
{
2010-07-07 11:36:20 +08:00
{ LLDB_OPT_SET_1 , false , " line " , ' l ' , required_argument , NULL , 0 , " <line> " , " The line number at which to start the display source. " } ,
{ LLDB_OPT_SET_1 , false , " file " , ' f ' , required_argument , NULL , CommandCompletions : : eSourceFileCompletion , " <file> " , " The file from which to display source. " } ,
{ 0 , false , NULL , 0 , 0 , NULL , 0 , NULL , NULL }
} ;
# pragma mark CommandObjectSourceList
//-------------------------------------------------------------------------
// CommandObjectSourceList
//-------------------------------------------------------------------------
2010-06-09 00:52:24 +08:00
2010-07-07 11:36:20 +08:00
class CommandObjectSourceList : public CommandObject
2010-06-09 00:52:24 +08:00
{
2010-07-07 11:36:20 +08:00
class CommandOptions : public Options
2010-06-09 00:52:24 +08:00
{
2010-07-07 11:36:20 +08:00
public :
CommandOptions ( ) :
Options ( )
{
}
2010-06-09 00:52:24 +08:00
2010-07-07 11:36:20 +08:00
~ CommandOptions ( )
{
}
2010-06-09 00:52:24 +08:00
2010-07-07 11:36:20 +08:00
Error
SetOptionValue ( int option_idx , const char * option_arg )
2010-06-09 00:52:24 +08:00
{
2010-07-07 11:36:20 +08:00
Error error ;
const char short_option = g_option_table [ option_idx ] . short_option ;
switch ( short_option )
{
case ' l ' :
start_line = Args : : StringToUInt32 ( option_arg , 0 ) ;
if ( start_line = = 0 )
error . SetErrorStringWithFormat ( " Invalid line number: '%s'. \n " , option_arg ) ;
break ;
2010-06-09 00:52:24 +08:00
2010-08-20 09:17:07 +08:00
case ' c ' :
2010-07-07 11:36:20 +08:00
num_lines = Args : : StringToUInt32 ( option_arg , 0 ) ;
if ( num_lines = = 0 )
error . SetErrorStringWithFormat ( " Invalid line count: '%s'. \n " , option_arg ) ;
break ;
2010-06-09 00:52:24 +08:00
2010-07-07 11:36:20 +08:00
case ' f ' :
file_name = option_arg ;
break ;
2010-08-20 09:17:07 +08:00
case ' n ' :
symbol_name = option_arg ;
break ;
2010-07-07 11:36:20 +08:00
2010-08-20 09:17:07 +08:00
case ' s ' :
m_modules . push_back ( std : : string ( option_arg ) ) ;
break ;
2010-07-07 11:36:20 +08:00
default :
error . SetErrorStringWithFormat ( " Unrecognized short option '%c'. \n " , short_option ) ;
break ;
2010-06-09 00:52:24 +08:00
}
2010-07-07 11:36:20 +08:00
return error ;
}
2010-06-09 00:52:24 +08:00
2010-07-07 11:36:20 +08:00
void
ResetOptionValues ( )
{
Options : : ResetOptionValues ( ) ;
file_spec . Clear ( ) ;
file_name . clear ( ) ;
2010-08-20 09:17:07 +08:00
symbol_name . clear ( ) ;
2010-07-07 11:36:20 +08:00
start_line = 0 ;
num_lines = 10 ;
2010-08-20 09:17:07 +08:00
m_modules . clear ( ) ;
2010-07-07 11:36:20 +08:00
}
const lldb : : OptionDefinition *
GetDefinitions ( )
{
return g_option_table ;
}
static lldb : : OptionDefinition g_option_table [ ] ;
// Instance variables to hold the values for command options.
FileSpec file_spec ;
std : : string file_name ;
2010-08-20 09:17:07 +08:00
std : : string symbol_name ;
2010-07-07 11:36:20 +08:00
uint32_t start_line ;
uint32_t num_lines ;
2010-08-20 09:17:07 +08:00
STLStringArray m_modules ;
2010-07-07 11:36:20 +08:00
} ;
public :
CommandObjectSourceList ( ) :
CommandObject ( " source list " ,
" Display source files from the current executable's debug info. " ,
" source list [<cmd-options>] [<filename>] " )
{
}
~ CommandObjectSourceList ( )
{
}
Options *
GetOptions ( )
{
return & m_options ;
}
bool
Execute
(
CommandInterpreter & interpreter ,
Args & args ,
CommandReturnObject & result
)
{
const int argc = args . GetArgumentCount ( ) ;
if ( argc ! = 0 )
{
result . AppendErrorWithFormat ( " '%s' takes no arguments, only flags. \n " , GetCommandName ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
ExecutionContext exe_ctx ( interpreter . GetDebugger ( ) . GetExecutionContext ( ) ) ;
2010-08-20 09:17:07 +08:00
if ( ! m_options . symbol_name . empty ( ) )
{
// Displaying the source for a symbol:
2010-08-27 05:32:51 +08:00
Target * target = interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
2010-08-20 09:17:07 +08:00
if ( target = = NULL )
{
result . AppendError ( " invalid target, set executable file using 'file' command " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
SymbolContextList sc_list ;
ConstString name ( m_options . symbol_name . c_str ( ) ) ;
bool append = true ;
size_t num_matches = 0 ;
if ( m_options . m_modules . size ( ) > 0 )
{
ModuleList matching_modules ;
for ( int i = 0 ; i < m_options . m_modules . size ( ) ; i + + )
{
FileSpec module_spec ( m_options . m_modules [ i ] . c_str ( ) ) ;
if ( module_spec )
{
matching_modules . Clear ( ) ;
target - > GetImages ( ) . FindModules ( & module_spec , NULL , NULL , NULL , matching_modules ) ;
num_matches + = matching_modules . FindFunctions ( name , eFunctionNameTypeBase , append , sc_list ) ;
}
}
}
else
{
num_matches = target - > GetImages ( ) . FindFunctions ( name , eFunctionNameTypeBase , append , sc_list ) ;
}
SymbolContext sc ;
if ( num_matches = = 0 )
{
result . AppendErrorWithFormat ( " Could not find function named: \" %s \" . \n " , m_options . symbol_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
sc_list . GetContextAtIndex ( 0 , sc ) ;
FileSpec start_file ;
uint32_t start_line ;
uint32_t end_line ;
FileSpec end_file ;
if ( sc . function ! = NULL )
{
sc . function - > GetStartLineSourceInfo ( start_file , start_line ) ;
if ( start_line = = 0 )
{
result . AppendErrorWithFormat ( " Could not find line information for start of function: \" %s \" . \n " , m_options . symbol_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
sc . function - > GetEndLineSourceInfo ( end_file , end_line ) ;
}
else
{
result . AppendErrorWithFormat ( " Could not find function info for: \" %s \" . \n " , m_options . symbol_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( num_matches > 1 )
{
// This could either be because there are multiple functions of this name, in which case
// we'll have to specify this further... Or it could be because there are multiple inlined instances
// of one function. So run through the matches and if they all have the same file & line then we can just
// list one.
bool found_multiple = false ;
for ( size_t i = 1 ; i < num_matches ; i + + )
{
SymbolContext scratch_sc ;
sc_list . GetContextAtIndex ( i , scratch_sc ) ;
if ( scratch_sc . function ! = NULL )
{
FileSpec scratch_file ;
uint32_t scratch_line ;
scratch_sc . function - > GetStartLineSourceInfo ( scratch_file , scratch_line ) ;
if ( scratch_file ! = start_file
| | scratch_line ! = start_line )
{
found_multiple = true ;
break ;
}
}
}
if ( found_multiple )
{
StreamString s ;
for ( size_t i = 0 ; i < num_matches ; i + + )
{
SymbolContext scratch_sc ;
sc_list . GetContextAtIndex ( i , scratch_sc ) ;
if ( scratch_sc . function ! = NULL )
{
s . Printf ( " \n %d: " , i ) ;
scratch_sc . function - > Dump ( & s , true ) ;
}
}
result . AppendErrorWithFormat ( " Multiple functions found matching: %s: \n %s \n " ,
m_options . symbol_name . c_str ( ) ,
s . GetData ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
// This is a little hacky, but the first line table entry for a function points to the "{" that
// starts the function block. It would be nice to actually get the function
// declaration in there too. So back up a bit, but not further than what you're going to display.
size_t lines_to_back_up = m_options . num_lines > = 10 ? 5 : m_options . num_lines / 2 ;
uint32_t line_no ;
if ( start_line < = lines_to_back_up )
line_no = 1 ;
else
line_no = start_line - lines_to_back_up ;
// For fun, if the function is shorter than the number of lines we're supposed to display,
// only display the function...
if ( end_line ! = 0 )
{
if ( m_options . num_lines > end_line - line_no )
m_options . num_lines = end_line - line_no ;
}
char path_buf [ PATH_MAX + 1 ] ;
start_file . GetPath ( path_buf , PATH_MAX ) ;
result . AppendMessageWithFormat ( " File: %s. \n " , path_buf ) ;
interpreter . GetDebugger ( ) . GetSourceManager ( ) . DisplaySourceLinesWithLineNumbers ( start_file ,
line_no ,
0 ,
m_options . num_lines ,
" " ,
& result . GetOutputStream ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
return true ;
}
else if ( m_options . file_name . empty ( ) )
2010-07-07 11:36:20 +08:00
{
// Last valid source manager context, or the current frame if no
// valid last context in source manager.
// One little trick here, if you type the exact same list command twice in a row, it is
// more likely because you typed it once, then typed it again
if ( m_options . start_line = = 0 )
{
if ( interpreter . GetDebugger ( ) . GetSourceManager ( ) . DisplayMoreWithLineNumbers ( & result . GetOutputStream ( ) ) )
2010-06-09 00:52:24 +08:00
{
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
2010-07-07 11:36:20 +08:00
}
else
{
if ( interpreter . GetDebugger ( ) . GetSourceManager ( ) . DisplaySourceLinesWithLineNumbersUsingLastFile (
m_options . start_line , // Line to display
0 , // Lines before line to display
m_options . num_lines , // Lines after line to display
" " , // Don't mark "line"
& result . GetOutputStream ( ) ) )
2010-06-09 00:52:24 +08:00
{
2010-07-07 11:36:20 +08:00
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
2010-06-09 00:52:24 +08:00
}
2010-07-07 11:36:20 +08:00
2010-06-09 00:52:24 +08:00
}
}
else
{
2010-07-07 11:36:20 +08:00
const char * filename = m_options . file_name . c_str ( ) ;
2010-08-27 05:32:51 +08:00
Target * target = interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
2010-07-07 11:36:20 +08:00
if ( target = = NULL )
{
result . AppendError ( " invalid target, set executable file using 'file' command " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2010-06-09 00:52:24 +08:00
2010-07-07 11:36:20 +08:00
bool check_inlines = false ;
SymbolContextList sc_list ;
2010-08-20 09:17:07 +08:00
size_t num_matches = 0 ;
if ( m_options . m_modules . size ( ) > 0 )
{
ModuleList matching_modules ;
for ( int i = 0 ; i < m_options . m_modules . size ( ) ; i + + )
{
FileSpec module_spec ( m_options . m_modules [ i ] . c_str ( ) ) ;
if ( module_spec )
{
matching_modules . Clear ( ) ;
target - > GetImages ( ) . FindModules ( & module_spec , NULL , NULL , NULL , matching_modules ) ;
num_matches + = matching_modules . ResolveSymbolContextForFilePath ( filename ,
0 ,
check_inlines ,
eSymbolContextModule | eSymbolContextCompUnit ,
sc_list ) ;
}
}
}
else
{
num_matches = target - > GetImages ( ) . ResolveSymbolContextForFilePath ( filename ,
0 ,
check_inlines ,
eSymbolContextModule | eSymbolContextCompUnit ,
sc_list ) ;
}
if ( num_matches = = 0 )
{
result . AppendErrorWithFormat ( " Could not find source file \" %s \" . \n " ,
m_options . file_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( num_matches > 1 )
2010-07-07 11:36:20 +08:00
{
SymbolContext sc ;
2010-08-20 09:17:07 +08:00
bool got_multiple = false ;
FileSpec * test_cu_spec = NULL ;
for ( int i = 0 ; i < num_matches ; i + + )
2010-07-07 11:36:20 +08:00
{
2010-08-20 09:17:07 +08:00
sc_list . GetContextAtIndex ( i , sc ) ;
2010-07-07 11:36:20 +08:00
if ( sc . comp_unit )
{
2010-08-20 09:17:07 +08:00
if ( test_cu_spec )
{
if ( test_cu_spec ! = static_cast < FileSpec * > ( sc . comp_unit ) )
got_multiple = true ;
break ;
}
else
test_cu_spec = sc . comp_unit ;
2010-07-07 11:36:20 +08:00
}
}
2010-08-20 09:17:07 +08:00
if ( got_multiple )
{
result . AppendErrorWithFormat ( " Multiple source files found matching: \" %s. \" \n " ,
m_options . file_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
SymbolContext sc ;
if ( sc_list . GetContextAtIndex ( 0 , sc ) )
{
if ( sc . comp_unit )
{
interpreter . GetDebugger ( ) . GetSourceManager ( ) . DisplaySourceLinesWithLineNumbers ( sc . comp_unit ,
m_options . start_line ,
0 ,
m_options . num_lines ,
" " ,
& result . GetOutputStream ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
}
else
{
result . AppendErrorWithFormat ( " No comp unit found for: \" %s. \" \n " ,
m_options . file_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
2010-07-07 11:36:20 +08:00
}
2010-06-09 00:52:24 +08:00
}
2010-07-07 11:36:20 +08:00
return result . Succeeded ( ) ;
2010-06-09 00:52:24 +08:00
}
2010-07-07 11:36:20 +08:00
virtual const char * GetRepeatCommand ( Args & current_command_args , uint32_t index )
2010-06-09 00:52:24 +08:00
{
2010-07-07 11:36:20 +08:00
return m_cmd_name . c_str ( ) ;
2010-06-09 00:52:24 +08:00
}
2010-07-07 11:36:20 +08:00
protected :
CommandOptions m_options ;
} ;
lldb : : OptionDefinition
CommandObjectSourceList : : CommandOptions : : g_option_table [ ] =
{
2010-08-20 09:17:07 +08:00
{ LLDB_OPT_SET_ALL , false , " count " , ' c ' , required_argument , NULL , 0 , " <count> " , " The number of source lines to display. " } ,
{ LLDB_OPT_SET_ALL , false , " shlib " , ' s ' , required_argument , NULL , CommandCompletions : : eModuleCompletion , " <shlib-name> " ,
" Look up the source file in the given shared library. " } ,
2010-07-07 11:36:20 +08:00
{ LLDB_OPT_SET_1 , false , " file " , ' f ' , required_argument , NULL , CommandCompletions : : eSourceFileCompletion , " <file> " , " The file from which to display source. " } ,
2010-08-20 09:17:07 +08:00
{ LLDB_OPT_SET_1 , false , " line " , ' l ' , required_argument , NULL , 0 , " <line> " , " The line number at which to start the display source. " } ,
{ LLDB_OPT_SET_2 , false , " name " , ' n ' , required_argument , NULL , CommandCompletions : : eSymbolCompletion , " <symbol> " , " The name of a function whose source to display. " } ,
2010-07-07 11:36:20 +08:00
{ 0 , false , NULL , 0 , 0 , NULL , 0 , NULL , NULL }
} ;
# pragma mark CommandObjectMultiwordSource
//-------------------------------------------------------------------------
// CommandObjectMultiwordSource
//-------------------------------------------------------------------------
CommandObjectMultiwordSource : : CommandObjectMultiwordSource ( CommandInterpreter & interpreter ) :
CommandObjectMultiword ( " source " ,
" Commands for accessing source file information " ,
" source <subcommand> [<subcommand-options>] " )
{
LoadSubCommand ( interpreter , " info " , CommandObjectSP ( new CommandObjectSourceInfo ( ) ) ) ;
LoadSubCommand ( interpreter , " list " , CommandObjectSP ( new CommandObjectSourceList ( ) ) ) ;
}
CommandObjectMultiwordSource : : ~ CommandObjectMultiwordSource ( )
{
2010-06-09 00:52:24 +08:00
}
2010-07-07 11:36:20 +08:00