2010-06-09 00:52:24 +08:00
//===-- CommandObjectDisassemble.cpp ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
2016-02-20 08:58:29 +08:00
# include "CommandObjectDisassemble.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Core/AddressRange.h"
<rdar://problem/11757916>
Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes:
- Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file".
- modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly
- Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was.
- modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile()
Cleaned up header includes a bit as well.
llvm-svn: 162860
2012-08-30 05:13:06 +08:00
# include "lldb/Core/Disassembler.h"
2013-04-11 11:14:01 +08:00
# include "lldb/Core/Module.h"
<rdar://problem/11757916>
Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes:
- Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file".
- modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly
- Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was.
- modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile()
Cleaned up header includes a bit as well.
llvm-svn: 162860
2012-08-30 05:13:06 +08:00
# include "lldb/Core/SourceManager.h"
2017-03-23 07:33:16 +08:00
# include "lldb/Host/OptionParser.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Interpreter/CommandCompletions.h"
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/CommandReturnObject.h"
2010-06-16 03:49:27 +08:00
# include "lldb/Interpreter/Options.h"
<rdar://problem/11757916>
Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes:
- Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file".
- modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly
- Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was.
- modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile()
Cleaned up header includes a bit as well.
llvm-svn: 162860
2012-08-30 05:13:06 +08:00
# include "lldb/Symbol/Function.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Symbol/Symbol.h"
# include "lldb/Target/Process.h"
2013-12-06 09:12:00 +08:00
# include "lldb/Target/SectionLoadList.h"
2013-11-04 17:33:30 +08:00
# include "lldb/Target/StackFrame.h"
2010-06-09 00:52:24 +08:00
# include "lldb/Target/Target.h"
# define DEFAULT_DISASM_BYTE_SIZE 32
2016-09-07 04:57:50 +08:00
# define DEFAULT_DISASM_NUM_INS 4
2010-06-09 00:52:24 +08:00
using namespace lldb ;
using namespace lldb_private ;
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
static OptionDefinition g_disassemble_options [ ] = {
// clang-format off
{ LLDB_OPT_SET_ALL , false , " bytes " , ' b ' , OptionParser : : eNoArgument , nullptr , nullptr , 0 , eArgTypeNone , " Show opcode bytes when disassembling. " } ,
{ LLDB_OPT_SET_ALL , false , " context " , ' C ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeNumLines , " Number of context lines of source to show. " } ,
{ LLDB_OPT_SET_ALL , false , " mixed " , ' m ' , OptionParser : : eNoArgument , nullptr , nullptr , 0 , eArgTypeNone , " Enable mixed source and assembly display. " } ,
{ LLDB_OPT_SET_ALL , false , " raw " , ' r ' , OptionParser : : eNoArgument , nullptr , nullptr , 0 , eArgTypeNone , " Print raw disassembly with no symbol information. " } ,
{ LLDB_OPT_SET_ALL , false , " plugin " , ' P ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypePlugin , " Name of the disassembler plugin you want to use. " } ,
{ LLDB_OPT_SET_ALL , false , " flavor " , ' F ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeDisassemblyFlavor , " Name of the disassembly flavor you want to use. "
" Currently the only valid options are default, and for Intel "
" architectures, att and intel. " } ,
{ LLDB_OPT_SET_ALL , false , " arch " , ' A ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeArchitecture , " Specify the architecture to use from cross disassembly. " } ,
{ LLDB_OPT_SET_1 |
LLDB_OPT_SET_2 , true , " start-address " , ' s ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeAddressOrExpression , " Address at which to start disassembling. " } ,
{ LLDB_OPT_SET_1 , false , " end-address " , ' e ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeAddressOrExpression , " Address at which to end disassembling. " } ,
{ LLDB_OPT_SET_2 |
LLDB_OPT_SET_3 |
LLDB_OPT_SET_4 |
LLDB_OPT_SET_5 , false , " count " , ' c ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeNumLines , " Number of instructions to display. " } ,
{ LLDB_OPT_SET_3 , false , " name " , ' n ' , OptionParser : : eRequiredArgument , nullptr , nullptr , CommandCompletions : : eSymbolCompletion , eArgTypeFunctionName , " Disassemble entire contents of the given function name. " } ,
{ LLDB_OPT_SET_4 , false , " frame " , ' f ' , OptionParser : : eNoArgument , nullptr , nullptr , 0 , eArgTypeNone , " Disassemble from the start of the current frame's function. " } ,
{ LLDB_OPT_SET_5 , false , " pc " , ' p ' , OptionParser : : eNoArgument , nullptr , nullptr , 0 , eArgTypeNone , " Disassemble around the current pc. " } ,
{ LLDB_OPT_SET_6 , false , " line " , ' l ' , OptionParser : : eNoArgument , nullptr , nullptr , 0 , eArgTypeNone , " Disassemble the current frame's current source line instructions if there is debug line "
" table information, else disassemble around the pc. " } ,
{ LLDB_OPT_SET_7 , false , " address " , ' a ' , OptionParser : : eRequiredArgument , nullptr , nullptr , 0 , eArgTypeAddressOrExpression , " Disassemble function containing this address. " } ,
// clang-format on
} ;
2016-09-07 04:57:50 +08:00
CommandObjectDisassemble : : CommandOptions : : CommandOptions ( )
: Options ( ) , num_lines_context ( 0 ) , num_instructions ( 0 ) , func_name ( ) ,
current_function ( false ) , start_addr ( ) , end_addr ( ) , at_pc ( false ) ,
frame_line ( false ) , plugin_name ( ) , flavor_string ( ) , arch ( ) ,
some_location_specified ( false ) , symbol_containing_addr ( ) {
OptionParsingStarting ( nullptr ) ;
2010-06-09 00:52:24 +08:00
}
2016-02-20 08:58:29 +08:00
CommandObjectDisassemble : : CommandOptions : : ~ CommandOptions ( ) = default ;
2010-06-09 00:52:24 +08:00
2017-05-12 12:51:55 +08:00
Status CommandObjectDisassemble : : CommandOptions : : SetOptionValue (
2016-11-13 00:56:47 +08:00
uint32_t option_idx , llvm : : StringRef option_arg ,
2016-09-07 04:57:50 +08:00
ExecutionContext * execution_context ) {
2017-05-12 12:51:55 +08:00
Status error ;
2016-09-07 04:57:50 +08:00
const int short_option = m_getopt_table [ option_idx ] . val ;
switch ( short_option ) {
case ' m ' :
show_mixed = true ;
break ;
case ' C ' :
2016-11-13 00:56:47 +08:00
if ( option_arg . getAsInteger ( 0 , num_lines_context ) )
2016-09-07 04:57:50 +08:00
error . SetErrorStringWithFormat ( " invalid num context lines string: \" %s \" " ,
2016-11-13 00:56:47 +08:00
option_arg . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' c ' :
2016-11-13 00:56:47 +08:00
if ( option_arg . getAsInteger ( 0 , num_instructions ) )
2016-09-07 04:57:50 +08:00
error . SetErrorStringWithFormat (
2016-11-13 00:56:47 +08:00
" invalid num of instructions string: \" %s \" " ,
option_arg . str ( ) . c_str ( ) ) ;
2016-09-07 04:57:50 +08:00
break ;
case ' b ' :
show_bytes = true ;
break ;
case ' s ' : {
start_addr = Args : : StringToAddress ( execution_context , option_arg ,
LLDB_INVALID_ADDRESS , & error ) ;
if ( start_addr ! = LLDB_INVALID_ADDRESS )
some_location_specified = true ;
} break ;
case ' e ' : {
end_addr = Args : : StringToAddress ( execution_context , option_arg ,
LLDB_INVALID_ADDRESS , & error ) ;
if ( end_addr ! = LLDB_INVALID_ADDRESS )
some_location_specified = true ;
} break ;
case ' n ' :
func_name . assign ( option_arg ) ;
some_location_specified = true ;
break ;
case ' p ' :
at_pc = true ;
some_location_specified = true ;
break ;
case ' l ' :
frame_line = true ;
// Disassemble the current source line kind of implies showing mixed
// source code context.
show_mixed = true ;
some_location_specified = true ;
break ;
case ' P ' :
plugin_name . assign ( option_arg ) ;
break ;
case ' F ' : {
TargetSP target_sp =
execution_context ? execution_context - > GetTargetSP ( ) : TargetSP ( ) ;
if ( target_sp & & ( target_sp - > GetArchitecture ( ) . GetTriple ( ) . getArch ( ) = =
llvm : : Triple : : x86 | |
target_sp - > GetArchitecture ( ) . GetTriple ( ) . getArch ( ) = =
llvm : : Triple : : x86_64 ) ) {
flavor_string . assign ( option_arg ) ;
} else
error . SetErrorStringWithFormat ( " Disassembler flavors are currently only "
" supported for x86 and x86_64 targets. " ) ;
break ;
}
case ' r ' :
raw = true ;
break ;
case ' f ' :
current_function = true ;
some_location_specified = true ;
break ;
case ' A ' :
if ( execution_context ) {
auto target_sp =
execution_context ? execution_context - > GetTargetSP ( ) : TargetSP ( ) ;
auto platform_sp = target_sp ? target_sp - > GetPlatform ( ) : PlatformSP ( ) ;
2017-10-31 18:56:03 +08:00
arch = Platform : : GetAugmentedArchSpec ( platform_sp . get ( ) , option_arg ) ;
2016-09-07 04:57:50 +08:00
}
break ;
2013-04-11 11:14:01 +08:00
2016-09-07 04:57:50 +08:00
case ' a ' : {
symbol_containing_addr = Args : : StringToAddress (
execution_context , option_arg , LLDB_INVALID_ADDRESS , & error ) ;
if ( symbol_containing_addr ! = LLDB_INVALID_ADDRESS ) {
some_location_specified = true ;
2010-06-09 00:52:24 +08:00
}
2016-09-07 04:57:50 +08:00
} break ;
default :
error . SetErrorStringWithFormat ( " unrecognized short option '%c' " ,
short_option ) ;
break ;
}
2010-06-09 00:52:24 +08:00
2016-09-07 04:57:50 +08:00
return error ;
2010-06-09 00:52:24 +08:00
}
2016-09-07 04:57:50 +08:00
void CommandObjectDisassemble : : CommandOptions : : OptionParsingStarting (
ExecutionContext * execution_context ) {
show_mixed = false ;
show_bytes = false ;
num_lines_context = 0 ;
num_instructions = 0 ;
func_name . clear ( ) ;
current_function = false ;
at_pc = false ;
frame_line = false ;
start_addr = LLDB_INVALID_ADDRESS ;
end_addr = LLDB_INVALID_ADDRESS ;
symbol_containing_addr = LLDB_INVALID_ADDRESS ;
raw = false ;
plugin_name . clear ( ) ;
Target * target =
execution_context ? execution_context - > GetTargetPtr ( ) : nullptr ;
// This is a hack till we get the ability to specify features based on
// architecture. For now GetDisassemblyFlavor
// is really only valid for x86 (and for the llvm assembler plugin, but I'm
// papering over that since that is the
// only disassembler plugin we have...
if ( target ) {
if ( target - > GetArchitecture ( ) . GetTriple ( ) . getArch ( ) = = llvm : : Triple : : x86 | |
target - > GetArchitecture ( ) . GetTriple ( ) . getArch ( ) = =
llvm : : Triple : : x86_64 ) {
flavor_string . assign ( target - > GetDisassemblyFlavor ( ) ) ;
} else
flavor_string . assign ( " default " ) ;
} else
flavor_string . assign ( " default " ) ;
arch . Clear ( ) ;
some_location_specified = false ;
2011-09-01 09:11:04 +08:00
}
2017-05-12 12:51:55 +08:00
Status CommandObjectDisassemble : : CommandOptions : : OptionParsingFinished (
2016-09-07 04:57:50 +08:00
ExecutionContext * execution_context ) {
if ( ! some_location_specified )
current_function = true ;
2017-05-12 12:51:55 +08:00
return Status ( ) ;
2010-06-09 00:52:24 +08:00
}
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-23 04:22:55 +08:00
llvm : : ArrayRef < OptionDefinition >
2016-09-07 04:57:50 +08:00
CommandObjectDisassemble : : CommandOptions : : GetDefinitions ( ) {
2016-09-23 05:06:13 +08:00
return llvm : : makeArrayRef ( g_disassemble_options ) ;
2010-06-09 00:52:24 +08:00
}
//-------------------------------------------------------------------------
// CommandObjectDisassemble
//-------------------------------------------------------------------------
2016-09-07 04:57:50 +08:00
CommandObjectDisassemble : : CommandObjectDisassemble (
CommandInterpreter & interpreter )
: CommandObjectParsed (
interpreter , " disassemble " ,
" Disassemble specified instructions in the current target. "
" Defaults to the current function for the current thread and "
" stack frame. " ,
" disassemble [<cmd-options>] " ) ,
m_options ( ) { }
2010-06-09 00:52:24 +08:00
2016-02-20 08:58:29 +08:00
CommandObjectDisassemble : : ~ CommandObjectDisassemble ( ) = default ;
2010-06-09 00:52:24 +08:00
2016-09-07 04:57:50 +08:00
bool CommandObjectDisassemble : : DoExecute ( Args & command ,
CommandReturnObject & result ) {
Target * target = m_interpreter . GetDebugger ( ) . GetSelectedTarget ( ) . get ( ) ;
if ( target = = nullptr ) {
result . AppendError ( " invalid target, create a debug target using the "
" 'target create' command " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( ! m_options . arch . IsValid ( ) )
m_options . arch = target - > GetArchitecture ( ) ;
if ( ! m_options . arch . IsValid ( ) ) {
result . AppendError (
" use the --arch option or set the target architecture to disassemble " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
const char * plugin_name = m_options . GetPluginName ( ) ;
const char * flavor_string = m_options . GetFlavorString ( ) ;
DisassemblerSP disassembler =
Disassembler : : FindPlugin ( m_options . arch , flavor_string , plugin_name ) ;
if ( ! disassembler ) {
if ( plugin_name ) {
result . AppendErrorWithFormat (
" Unable to find Disassembler plug-in named '%s' that supports the "
" '%s' architecture. \n " ,
plugin_name , m_options . arch . GetArchitectureName ( ) ) ;
} else
result . AppendErrorWithFormat (
" Unable to find Disassembler plug-in for the '%s' architecture. \n " ,
m_options . arch . GetArchitectureName ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
} else if ( flavor_string ! = nullptr & &
! disassembler - > FlavorValidForArchSpec ( m_options . arch ,
flavor_string ) )
result . AppendWarningWithFormat (
" invalid disassembler flavor \" %s \" , using default. \n " , flavor_string ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
2016-10-06 04:03:37 +08:00
if ( ! command . empty ( ) ) {
2016-09-07 04:57:50 +08:00
result . AppendErrorWithFormat (
" \" disassemble \" arguments are specified as options. \n " ) ;
const int terminal_width =
GetCommandInterpreter ( ) . GetDebugger ( ) . GetTerminalWidth ( ) ;
GetOptions ( ) - > GenerateOptionUsage ( result . GetErrorStream ( ) , this ,
terminal_width ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
if ( m_options . show_mixed & & m_options . num_lines_context = = 0 )
I'm experimenting with changing how the mixed source & assembly
mode in lldb works. I've been discussing this with Jim Ingham,
Greg Clayton, and Kate Stone for the past week or two.
Previously lldb would print three source lines (centered on the
line table entry line for the current line) followed by the assembly.
It would print the context information (module`function + offset)
before those three lines of source.
Now lldb will print up to two lines before/after the line table
entry. It prints two '*' characters for the line table line to
make it clear what line is showing assembly. There is one line of
whitespace before/after the source lines so the separation between
source & assembly is clearer. I don't print the context line
(module`function + offset). I stop printing context lines if it's
a different line table entry, or if it's a source line I've already
printed as context to another source line. If I have two line table
entries one after another for the same source line (I get these often
with clang - with different column information in them), I only print
the source line once.
I'm also using the target.process.thread.step-avoid-regexp setting
(which keeps you from stepping into STL functions that have been inlined
into your own code) and avoid printing any source lines from functions
that match that regexp.
When lldb disassembles into a new function, it will try to find the
declaration line # for the function and print all of the source lines
between the decl and the first line table entry (usually a { curly brace)
so we have a good chance of including the arguments, at least with the
debug info emitted by clang.
Finally, the # of source lines of context to show has been separated
from whether we're doing mixed source & assembly or not. Previously
specifying 0 lines of context would turn off mixed source & assembly.
I think there's room for improvement, and maybe some bugs I haven't
found yet, but it's in good enough shape to upstream and iterate at
this point.
I'm not sure how best to indicate which source line is the actual line
table # versus context lines. I'm using '**' right now. Both Kate
and Greg had the initial idea to reuse '->' (normally used to indicate
"currently executing source line") - I tried it but I wasn't thrilled,
I'm too used to the established meaning of ->.
Greg had the interesting idea of avoiding context source lines only
in two line table entries in the same source file. So we'd print
two lines before & after a source line, and then the next line table
entry (if it was on the next source line after those two context lines)
we'd display only the following two lines -- the previous two had just
been printed. If an inline source line was printed between these two,
though, we'd print the context lines for both of them. It's an
interesting idea, and I want to see how it works with both -O0 and -O3
codegen where we have different amounts of inlining.
<rdar://problem/27961419>
llvm-svn: 280906
2016-09-08 13:12:41 +08:00
m_options . num_lines_context = 2 ;
2016-09-07 04:57:50 +08:00
// Always show the PC in the disassembly
uint32_t options = Disassembler : : eOptionMarkPCAddress ;
// Mark the source line for the current PC only if we are doing mixed source
// and assembly
if ( m_options . show_mixed )
options | = Disassembler : : eOptionMarkPCSourceLine ;
if ( m_options . show_bytes )
options | = Disassembler : : eOptionShowBytes ;
if ( m_options . raw )
options | = Disassembler : : eOptionRawOuput ;
if ( ! m_options . func_name . empty ( ) ) {
ConstString name ( m_options . func_name . c_str ( ) ) ;
if ( Disassembler : : Disassemble (
m_interpreter . GetDebugger ( ) , m_options . arch , plugin_name ,
flavor_string , m_exe_ctx , name ,
nullptr , // Module *
I'm experimenting with changing how the mixed source & assembly
mode in lldb works. I've been discussing this with Jim Ingham,
Greg Clayton, and Kate Stone for the past week or two.
Previously lldb would print three source lines (centered on the
line table entry line for the current line) followed by the assembly.
It would print the context information (module`function + offset)
before those three lines of source.
Now lldb will print up to two lines before/after the line table
entry. It prints two '*' characters for the line table line to
make it clear what line is showing assembly. There is one line of
whitespace before/after the source lines so the separation between
source & assembly is clearer. I don't print the context line
(module`function + offset). I stop printing context lines if it's
a different line table entry, or if it's a source line I've already
printed as context to another source line. If I have two line table
entries one after another for the same source line (I get these often
with clang - with different column information in them), I only print
the source line once.
I'm also using the target.process.thread.step-avoid-regexp setting
(which keeps you from stepping into STL functions that have been inlined
into your own code) and avoid printing any source lines from functions
that match that regexp.
When lldb disassembles into a new function, it will try to find the
declaration line # for the function and print all of the source lines
between the decl and the first line table entry (usually a { curly brace)
so we have a good chance of including the arguments, at least with the
debug info emitted by clang.
Finally, the # of source lines of context to show has been separated
from whether we're doing mixed source & assembly or not. Previously
specifying 0 lines of context would turn off mixed source & assembly.
I think there's room for improvement, and maybe some bugs I haven't
found yet, but it's in good enough shape to upstream and iterate at
this point.
I'm not sure how best to indicate which source line is the actual line
table # versus context lines. I'm using '**' right now. Both Kate
and Greg had the initial idea to reuse '->' (normally used to indicate
"currently executing source line") - I tried it but I wasn't thrilled,
I'm too used to the established meaning of ->.
Greg had the interesting idea of avoiding context source lines only
in two line table entries in the same source file. So we'd print
two lines before & after a source line, and then the next line table
entry (if it was on the next source line after those two context lines)
we'd display only the following two lines -- the previous two had just
been printed. If an inline source line was printed between these two,
though, we'd print the context lines for both of them. It's an
interesting idea, and I want to see how it works with both -O0 and -O3
codegen where we have different amounts of inlining.
<rdar://problem/27961419>
llvm-svn: 280906
2016-09-08 13:12:41 +08:00
m_options . num_instructions , m_options . show_mixed ,
2016-09-07 04:57:50 +08:00
m_options . show_mixed ? m_options . num_lines_context : 0 , options ,
result . GetOutputStream ( ) ) ) {
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendErrorWithFormat ( " Unable to find symbol with name '%s'. \n " ,
name . GetCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2010-06-09 00:52:24 +08:00
}
2016-09-07 04:57:50 +08:00
} else {
std : : vector < AddressRange > ranges ;
AddressRange range ;
StackFrame * frame = m_exe_ctx . GetFramePtr ( ) ;
if ( m_options . frame_line ) {
if ( frame = = nullptr ) {
result . AppendError ( " Cannot disassemble around the current line without "
" a selected frame. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2010-06-09 00:52:24 +08:00
return false ;
2016-09-07 04:57:50 +08:00
}
LineEntry pc_line_entry (
frame - > GetSymbolContext ( eSymbolContextLineEntry ) . line_entry ) ;
if ( pc_line_entry . IsValid ( ) ) {
range = pc_line_entry . range ;
} else {
m_options . at_pc =
true ; // No line entry, so just disassemble around the current pc
m_options . show_mixed = false ;
}
} else if ( m_options . current_function ) {
if ( frame = = nullptr ) {
result . AppendError ( " Cannot disassemble around the current function "
" without a selected frame. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2010-06-09 00:52:24 +08:00
return false ;
2016-09-07 04:57:50 +08:00
}
Symbol * symbol = frame - > GetSymbolContext ( eSymbolContextSymbol ) . symbol ;
if ( symbol ) {
range . GetBaseAddress ( ) = symbol - > GetAddress ( ) ;
range . SetByteSize ( symbol - > GetByteSize ( ) ) ;
}
2010-06-09 00:52:24 +08:00
}
2016-09-07 04:57:50 +08:00
// Did the "m_options.frame_line" find a valid range already? If so
// skip the rest...
if ( range . GetByteSize ( ) = = 0 ) {
if ( m_options . at_pc ) {
if ( frame = = nullptr ) {
result . AppendError ( " Cannot disassemble around the current PC without "
" a selected frame. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2010-07-01 07:03:03 +08:00
}
2016-09-07 04:57:50 +08:00
range . GetBaseAddress ( ) = frame - > GetFrameCodeAddress ( ) ;
if ( m_options . num_instructions = = 0 ) {
// Disassembling at the PC always disassembles some number of
// instructions (not the whole function).
m_options . num_instructions = DEFAULT_DISASM_NUM_INS ;
2011-03-22 09:48:42 +08:00
}
2016-09-07 04:57:50 +08:00
ranges . push_back ( range ) ;
} else {
range . GetBaseAddress ( ) . SetOffset ( m_options . start_addr ) ;
if ( range . GetBaseAddress ( ) . IsValid ( ) ) {
if ( m_options . end_addr ! = LLDB_INVALID_ADDRESS ) {
if ( m_options . end_addr < = m_options . start_addr ) {
result . AppendErrorWithFormat (
" End address before start address. \n " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
2012-03-08 05:03:09 +08:00
}
2016-09-07 04:57:50 +08:00
range . SetByteSize ( m_options . end_addr - m_options . start_addr ) ;
}
ranges . push_back ( range ) ;
} else {
if ( m_options . symbol_containing_addr ! = LLDB_INVALID_ADDRESS & &
target ) {
if ( ! target - > GetSectionLoadList ( ) . IsEmpty ( ) ) {
bool failed = false ;
Address symbol_containing_address ;
if ( target - > GetSectionLoadList ( ) . ResolveLoadAddress (
m_options . symbol_containing_addr ,
symbol_containing_address ) ) {
ModuleSP module_sp ( symbol_containing_address . GetModule ( ) ) ;
SymbolContext sc ;
bool resolve_tail_call_address = true ; // PC can be one past the
// address range of the
// function.
module_sp - > ResolveSymbolContextForAddress (
symbol_containing_address , eSymbolContextEverything , sc ,
resolve_tail_call_address ) ;
if ( sc . function | | sc . symbol ) {
sc . GetAddressRange ( eSymbolContextFunction |
eSymbolContextSymbol ,
0 , false , range ) ;
} else {
failed = true ;
Many improvements to the Platform base class and subclasses. The base Platform
class now implements the Host functionality for a lot of things that make
sense by default so that subclasses can check:
int
PlatformSubclass::Foo ()
{
if (IsHost())
return Platform::Foo (); // Let the platform base class do the host specific stuff
// Platform subclass specific code...
int result = ...
return result;
}
Added new functions to the platform:
virtual const char *Platform::GetUserName (uint32_t uid);
virtual const char *Platform::GetGroupName (uint32_t gid);
The user and group names are cached locally so that remote platforms can avoid
sending packets multiple times to resolve this information.
Added the parent process ID to the ProcessInfo class.
Added a new ProcessInfoMatch class which helps us to match processes up
and changed the Host layer over to using this new class. The new class allows
us to search for processs:
1 - by name (equal to, starts with, ends with, contains, and regex)
2 - by pid
3 - And further check for parent pid == value, uid == value, gid == value,
euid == value, egid == value, arch == value, parent == value.
This is all hookup up to the "platform process list" command which required
adding dumping routines to dump process information. If the Host class
implements the process lookup routines, you can now lists processes on
your local machine:
machine1.foo.com % lldb
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
94727 244 username usergroup username usergroup x86_64-apple-darwin Xcode
92742 92710 username usergroup username usergroup i386-apple-darwin debugserver
This of course also works remotely with the lldb-platform:
machine1.foo.com % lldb-platform --listen 1234
machine2.foo.com % lldb
(lldb) platform create remote-macosx
Platform: remote-macosx
Connected: no
(lldb) platform connect connect://localhost:1444
Platform: remote-macosx
Triple: x86_64-apple-darwin
OS Version: 10.6.7 (10J869)
Kernel: Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386
Hostname: machine1.foo.com
Connected: yes
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99556 244 username usergroup username usergroup x86_64-apple-darwin trustevaluation
99548 65539 username usergroup username usergroup x86_64-apple-darwin lldb
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
The lldb-platform implements everything with the Host:: layer, so this should
"just work" for linux. I will probably be adding more stuff to the Host layer
for launching processes and attaching to processes so that this support should
eventually just work as well.
Modified the target to be able to be created with an architecture that differs
from the main executable. This is needed for iOS debugging since we can have
an "armv6" binary which can run on an "armv7" machine, so we want to be able
to do:
% lldb
(lldb) platform create remote-ios
(lldb) file --arch armv7 a.out
Where "a.out" is an armv6 executable. The platform then can correctly decide
to open all "armv7" images for all dependent shared libraries.
Modified the disassembly to show the current PC value. Example output:
(lldb) disassemble --frame
a.out`main:
0x1eb7: pushl %ebp
0x1eb8: movl %esp, %ebp
0x1eba: pushl %ebx
0x1ebb: subl $20, %esp
0x1ebe: calll 0x1ec3 ; main + 12 at test.c:18
0x1ec3: popl %ebx
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
0x1edb: leal 213(%ebx), %eax
0x1ee1: movl %eax, (%esp)
0x1ee4: calll 0x1f1e ; puts
0x1ee9: calll 0x1f0c ; getchar
0x1eee: movl $20, (%esp)
0x1ef5: calll 0x1e6a ; sleep_loop at test.c:6
0x1efa: movl $12, %eax
0x1eff: addl $20, %esp
0x1f02: popl %ebx
0x1f03: leave
0x1f04: ret
This can be handy when dealing with the new --line options that was recently
added:
(lldb) disassemble --line
a.out`main + 13 at test.c:19
18 {
-> 19 printf("Process: %i\n\n", getpid());
20 puts("Press any key to continue..."); getchar();
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
Modified the ModuleList to have a lookup based solely on a UUID. Since the
UUID is typically the MD5 checksum of a binary image, there is no need
to give the path and architecture when searching for a pre-existing
image in an image list.
Now that we support remote debugging a bit better, our lldb_private::Module
needs to be able to track what the original path for file was as the platform
knows it, as well as where the file is locally. The module has the two
following functions to retrieve both paths:
const FileSpec &Module::GetFileSpec () const;
const FileSpec &Module::GetPlatformFileSpec () const;
llvm-svn: 128563
2011-03-31 02:16:51 +08:00
}
2016-09-07 04:57:50 +08:00
} else {
failed = true ;
}
if ( failed ) {
result . AppendErrorWithFormat (
" Could not find function bounds for address 0x% " PRIx64
" \n " ,
m_options . symbol_containing_addr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
ranges . push_back ( range ) ;
} else {
for ( lldb : : ModuleSP module_sp : target - > GetImages ( ) . Modules ( ) ) {
lldb : : addr_t file_addr = m_options . symbol_containing_addr ;
Address file_address ;
if ( module_sp - > ResolveFileAddress ( file_addr , file_address ) ) {
SymbolContext sc ;
bool resolve_tail_call_address = true ; // PC can be one past
// the address range of
// the function.
module_sp - > ResolveSymbolContextForAddress (
file_address , eSymbolContextEverything , sc ,
resolve_tail_call_address ) ;
if ( sc . function | | sc . symbol ) {
sc . GetAddressRange ( eSymbolContextFunction |
eSymbolContextSymbol ,
0 , false , range ) ;
2014-04-04 01:16:17 +08:00
ranges . push_back ( range ) ;
2016-09-07 04:57:50 +08:00
}
2011-03-22 09:48:42 +08:00
}
2016-09-07 04:57:50 +08:00
}
2011-03-22 09:48:42 +08:00
}
2016-09-07 04:57:50 +08:00
}
2011-03-22 09:48:42 +08:00
}
2016-09-07 04:57:50 +08:00
}
} else
ranges . push_back ( range ) ;
if ( m_options . num_instructions ! = 0 ) {
if ( ranges . empty ( ) ) {
// The default action is to disassemble the current frame function.
if ( frame ) {
SymbolContext sc ( frame - > GetSymbolContext ( eSymbolContextFunction |
eSymbolContextSymbol ) ) ;
if ( sc . function )
range . GetBaseAddress ( ) =
sc . function - > GetAddressRange ( ) . GetBaseAddress ( ) ;
else if ( sc . symbol & & sc . symbol - > ValueIsAddress ( ) )
range . GetBaseAddress ( ) = sc . symbol - > GetAddress ( ) ;
else
range . GetBaseAddress ( ) = frame - > GetFrameCodeAddress ( ) ;
2011-03-22 09:48:42 +08:00
}
2016-09-07 04:57:50 +08:00
if ( ! range . GetBaseAddress ( ) . IsValid ( ) ) {
result . AppendError ( " invalid frame " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
}
bool print_sc_header = ranges . size ( ) > 1 ;
for ( AddressRange cur_range : ranges ) {
if ( Disassembler : : Disassemble (
m_interpreter . GetDebugger ( ) , m_options . arch , plugin_name ,
flavor_string , m_exe_ctx , cur_range . GetBaseAddress ( ) ,
I'm experimenting with changing how the mixed source & assembly
mode in lldb works. I've been discussing this with Jim Ingham,
Greg Clayton, and Kate Stone for the past week or two.
Previously lldb would print three source lines (centered on the
line table entry line for the current line) followed by the assembly.
It would print the context information (module`function + offset)
before those three lines of source.
Now lldb will print up to two lines before/after the line table
entry. It prints two '*' characters for the line table line to
make it clear what line is showing assembly. There is one line of
whitespace before/after the source lines so the separation between
source & assembly is clearer. I don't print the context line
(module`function + offset). I stop printing context lines if it's
a different line table entry, or if it's a source line I've already
printed as context to another source line. If I have two line table
entries one after another for the same source line (I get these often
with clang - with different column information in them), I only print
the source line once.
I'm also using the target.process.thread.step-avoid-regexp setting
(which keeps you from stepping into STL functions that have been inlined
into your own code) and avoid printing any source lines from functions
that match that regexp.
When lldb disassembles into a new function, it will try to find the
declaration line # for the function and print all of the source lines
between the decl and the first line table entry (usually a { curly brace)
so we have a good chance of including the arguments, at least with the
debug info emitted by clang.
Finally, the # of source lines of context to show has been separated
from whether we're doing mixed source & assembly or not. Previously
specifying 0 lines of context would turn off mixed source & assembly.
I think there's room for improvement, and maybe some bugs I haven't
found yet, but it's in good enough shape to upstream and iterate at
this point.
I'm not sure how best to indicate which source line is the actual line
table # versus context lines. I'm using '**' right now. Both Kate
and Greg had the initial idea to reuse '->' (normally used to indicate
"currently executing source line") - I tried it but I wasn't thrilled,
I'm too used to the established meaning of ->.
Greg had the interesting idea of avoiding context source lines only
in two line table entries in the same source file. So we'd print
two lines before & after a source line, and then the next line table
entry (if it was on the next source line after those two context lines)
we'd display only the following two lines -- the previous two had just
been printed. If an inline source line was printed between these two,
though, we'd print the context lines for both of them. It's an
interesting idea, and I want to see how it works with both -O0 and -O3
codegen where we have different amounts of inlining.
<rdar://problem/27961419>
llvm-svn: 280906
2016-09-08 13:12:41 +08:00
m_options . num_instructions , m_options . show_mixed ,
2016-09-07 04:57:50 +08:00
m_options . show_mixed ? m_options . num_lines_context : 0 , options ,
result . GetOutputStream ( ) ) ) {
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
if ( m_options . start_addr ! = LLDB_INVALID_ADDRESS )
result . AppendErrorWithFormat (
" Failed to disassemble memory at 0x%8.8 " PRIx64 " . \n " ,
m_options . start_addr ) ;
else if ( m_options . symbol_containing_addr ! = LLDB_INVALID_ADDRESS )
result . AppendErrorWithFormat (
" Failed to disassemble memory in function at 0x%8.8 " PRIx64
" . \n " ,
m_options . symbol_containing_addr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
if ( print_sc_header )
result . AppendMessage ( " \n " ) ;
} else {
if ( ranges . empty ( ) ) {
// The default action is to disassemble the current frame function.
if ( frame ) {
SymbolContext sc ( frame - > GetSymbolContext ( eSymbolContextFunction |
eSymbolContextSymbol ) ) ;
if ( sc . function )
range = sc . function - > GetAddressRange ( ) ;
else if ( sc . symbol & & sc . symbol - > ValueIsAddress ( ) ) {
range . GetBaseAddress ( ) = sc . symbol - > GetAddress ( ) ;
range . SetByteSize ( sc . symbol - > GetByteSize ( ) ) ;
} else
range . GetBaseAddress ( ) = frame - > GetFrameCodeAddress ( ) ;
} else {
result . AppendError ( " invalid frame " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
ranges . push_back ( range ) ;
}
bool print_sc_header = ranges . size ( ) > 1 ;
for ( AddressRange cur_range : ranges ) {
if ( cur_range . GetByteSize ( ) = = 0 )
cur_range . SetByteSize ( DEFAULT_DISASM_BYTE_SIZE ) ;
if ( Disassembler : : Disassemble (
m_interpreter . GetDebugger ( ) , m_options . arch , plugin_name ,
flavor_string , m_exe_ctx , cur_range , m_options . num_instructions ,
I'm experimenting with changing how the mixed source & assembly
mode in lldb works. I've been discussing this with Jim Ingham,
Greg Clayton, and Kate Stone for the past week or two.
Previously lldb would print three source lines (centered on the
line table entry line for the current line) followed by the assembly.
It would print the context information (module`function + offset)
before those three lines of source.
Now lldb will print up to two lines before/after the line table
entry. It prints two '*' characters for the line table line to
make it clear what line is showing assembly. There is one line of
whitespace before/after the source lines so the separation between
source & assembly is clearer. I don't print the context line
(module`function + offset). I stop printing context lines if it's
a different line table entry, or if it's a source line I've already
printed as context to another source line. If I have two line table
entries one after another for the same source line (I get these often
with clang - with different column information in them), I only print
the source line once.
I'm also using the target.process.thread.step-avoid-regexp setting
(which keeps you from stepping into STL functions that have been inlined
into your own code) and avoid printing any source lines from functions
that match that regexp.
When lldb disassembles into a new function, it will try to find the
declaration line # for the function and print all of the source lines
between the decl and the first line table entry (usually a { curly brace)
so we have a good chance of including the arguments, at least with the
debug info emitted by clang.
Finally, the # of source lines of context to show has been separated
from whether we're doing mixed source & assembly or not. Previously
specifying 0 lines of context would turn off mixed source & assembly.
I think there's room for improvement, and maybe some bugs I haven't
found yet, but it's in good enough shape to upstream and iterate at
this point.
I'm not sure how best to indicate which source line is the actual line
table # versus context lines. I'm using '**' right now. Both Kate
and Greg had the initial idea to reuse '->' (normally used to indicate
"currently executing source line") - I tried it but I wasn't thrilled,
I'm too used to the established meaning of ->.
Greg had the interesting idea of avoiding context source lines only
in two line table entries in the same source file. So we'd print
two lines before & after a source line, and then the next line table
entry (if it was on the next source line after those two context lines)
we'd display only the following two lines -- the previous two had just
been printed. If an inline source line was printed between these two,
though, we'd print the context lines for both of them. It's an
interesting idea, and I want to see how it works with both -O0 and -O3
codegen where we have different amounts of inlining.
<rdar://problem/27961419>
llvm-svn: 280906
2016-09-08 13:12:41 +08:00
m_options . show_mixed ,
2016-09-07 04:57:50 +08:00
m_options . show_mixed ? m_options . num_lines_context : 0 , options ,
result . GetOutputStream ( ) ) ) {
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
} else {
result . AppendErrorWithFormat (
" Failed to disassemble memory at 0x%8.8 " PRIx64 " . \n " ,
m_options . start_addr ) ;
result . SetStatus ( eReturnStatusFailed ) ;
2010-06-09 00:52:24 +08:00
}
2016-09-07 04:57:50 +08:00
if ( print_sc_header )
result . AppendMessage ( " \n " ) ;
}
2010-06-09 00:52:24 +08:00
}
2016-09-07 04:57:50 +08:00
}
2010-06-09 00:52:24 +08:00
2016-09-07 04:57:50 +08:00
return result . Succeeded ( ) ;
2010-06-09 00:52:24 +08:00
}