llvm-project/lldb/source/Commands/CommandObjectArgs.cpp

234 lines
7.4 KiB
C++
Raw Normal View History

//===-- CommandObjectArgs.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
#include "CommandObjectArgs.h"
#include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.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/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Value.h"
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "llvm/ADT/StringSwitch.h"
using namespace lldb;
using namespace lldb_private;
// This command is a toy. I'm just using it to have a way to construct the
// arguments to
// calling functions.
//
static OptionDefinition g_arg_options[] = {
// clang-format off
{ LLDB_OPT_SET_1, false, "debug", 'g', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable verbose debug logging of the expression parsing and evaluation." },
// clang-format on
};
CommandObjectArgs::CommandOptions::CommandOptions(
CommandInterpreter &interpreter)
: Options() {
// Keep only one place to reset the values to their defaults
OptionParsingStarting(nullptr);
}
CommandObjectArgs::CommandOptions::~CommandOptions() = default;
Error CommandObjectArgs::CommandOptions::SetOptionValue(
uint32_t option_idx, llvm::StringRef option_arg,
ExecutionContext *execution_context) {
Error error;
const int short_option = m_getopt_table[option_idx].val;
error.SetErrorStringWithFormat("invalid short option character '%c'",
short_option);
return error;
}
void CommandObjectArgs::CommandOptions::OptionParsingStarting(
ExecutionContext *execution_context) {}
llvm::ArrayRef<OptionDefinition>
CommandObjectArgs::CommandOptions::GetDefinitions() {
return llvm::makeArrayRef(g_arg_options);
}
CommandObjectArgs::CommandObjectArgs(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "args",
"When stopped at the start of a function, reads "
"function arguments of type (u?)int(8|16|32|64)_t, "
"(void|char)*",
"args"),
m_options(interpreter) {}
CommandObjectArgs::~CommandObjectArgs() = default;
Options *CommandObjectArgs::GetOptions() { return &m_options; }
bool CommandObjectArgs::DoExecute(Args &args, CommandReturnObject &result) {
ConstString target_triple;
Process *process = m_exe_ctx.GetProcessPtr();
if (!process) {
result.AppendError("Args found no process.");
result.SetStatus(eReturnStatusFailed);
return false;
}
const ABI *abi = process->GetABI().get();
if (!abi) {
result.AppendError("The current process has no ABI.");
result.SetStatus(eReturnStatusFailed);
return false;
}
if (args.empty()) {
result.AppendError("args requires at least one argument");
result.SetStatus(eReturnStatusFailed);
return false;
}
Thread *thread = m_exe_ctx.GetThreadPtr();
if (!thread) {
result.AppendError("args found no thread.");
result.SetStatus(eReturnStatusFailed);
return false;
}
lldb::StackFrameSP thread_cur_frame = thread->GetSelectedFrame();
if (!thread_cur_frame) {
result.AppendError("The current thread has no current frame.");
result.SetStatus(eReturnStatusFailed);
return false;
}
ModuleSP thread_module_sp(
thread_cur_frame->GetFrameCodeAddress().GetModule());
if (!thread_module_sp) {
result.AppendError("The PC has no associated module.");
result.SetStatus(eReturnStatusFailed);
return false;
}
TypeSystem *type_system =
thread_module_sp->GetTypeSystemForLanguage(eLanguageTypeC);
if (type_system == nullptr) {
result.AppendError("Unable to create C type system.");
result.SetStatus(eReturnStatusFailed);
return false;
}
ValueList value_list;
for (auto &arg_entry : args.entries()) {
llvm::StringRef arg_type = arg_entry.ref;
Value value;
value.SetValueType(Value::eValueTypeScalar);
CompilerType compiler_type;
std::size_t int_pos = arg_type.find("int");
if (int_pos != llvm::StringRef::npos) {
Encoding encoding = eEncodingSint;
int width = 0;
if (int_pos > 1) {
result.AppendErrorWithFormat("Invalid format: %s.\n",
arg_entry.c_str());
result.SetStatus(eReturnStatusFailed);
return false;
}
if (int_pos == 1 && arg_type[0] != 'u') {
result.AppendErrorWithFormat("Invalid format: %s.\n",
arg_entry.c_str());
result.SetStatus(eReturnStatusFailed);
return false;
}
if (arg_type[0] == 'u') {
encoding = eEncodingUint;
}
llvm::StringRef width_spec = arg_type.drop_front(int_pos + 3);
auto exp_result = llvm::StringSwitch<llvm::Optional<int>>(width_spec)
.Case("8_t", 8)
.Case("16_t", 16)
.Case("32_t", 32)
.Case("64_t", 64)
.Default(llvm::None);
if (!exp_result.hasValue()) {
result.AppendErrorWithFormat("Invalid format: %s.\n",
arg_entry.c_str());
result.SetStatus(eReturnStatusFailed);
return false;
}
width = *exp_result;
compiler_type =
type_system->GetBuiltinTypeForEncodingAndBitSize(encoding, width);
TypeSystem is now a plugin interface and removed any "ClangASTContext &Class::GetClangASTContext()" functions. This cleans up type systems to be more pluggable. Prior to this we had issues: - Module, SymbolFile, and many others has "ClangASTContext &GetClangASTContext()" functions. All have been switched over to use "TypeSystem *GetTypeSystemForLanguage()" - Cleaned up any places that were using the GetClangASTContext() functions to use TypeSystem - Cleaned up Module so that it no longer has dedicated type system member variables: lldb::ClangASTContextUP m_ast; ///< The Clang AST context for this module. lldb::GoASTContextUP m_go_ast; ///< The Go AST context for this module. Now we have a type system map: typedef std::map<lldb::LanguageType, lldb::TypeSystemSP> TypeSystemMap; TypeSystemMap m_type_system_map; ///< A map of any type systems associated with this module - Many places in code were using ClangASTContext static functions to place with CompilerType objects and add modifiers (const, volatile, restrict) and to make typedefs, L and R value references and more. These have been made into CompilerType functions that are abstract: class CompilerType { ... //---------------------------------------------------------------------- // Return a new CompilerType that is a L value reference to this type if // this type is valid and the type system supports L value references, // else return an invalid type. //---------------------------------------------------------------------- CompilerType GetLValueReferenceType () const; //---------------------------------------------------------------------- // Return a new CompilerType that is a R value reference to this type if // this type is valid and the type system supports R value references, // else return an invalid type. //---------------------------------------------------------------------- CompilerType GetRValueReferenceType () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a const modifier to this type if // this type is valid and the type system supports const modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddConstModifier () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a volatile modifier to this type if // this type is valid and the type system supports volatile modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddVolatileModifier () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a restrict modifier to this type if // this type is valid and the type system supports restrict modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddRestrictModifier () const; //---------------------------------------------------------------------- // Create a typedef to this type using "name" as the name of the typedef // this type is valid and the type system supports typedefs, else return // an invalid type. //---------------------------------------------------------------------- CompilerType CreateTypedef (const char *name, const CompilerDeclContext &decl_ctx) const; }; Other changes include: - Removed "CompilerType TypeSystem::GetIntTypeFromBitSize(...)" and CompilerType TypeSystem::GetFloatTypeFromBitSize(...) and replaced it with "CompilerType TypeSystem::GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, size_t bit_size);" - Fixed code in Type.h to not request the full type for a type for no good reason, just request the forward type and let the type expand as needed llvm-svn: 247953
2015-09-18 06:23:34 +08:00
if (!compiler_type.IsValid()) {
result.AppendErrorWithFormat(
"Couldn't get Clang type for format %s (%s integer, width %d).\n",
arg_entry.c_str(),
(encoding == eEncodingSint ? "signed" : "unsigned"), width);
result.SetStatus(eReturnStatusFailed);
TypeSystem is now a plugin interface and removed any "ClangASTContext &Class::GetClangASTContext()" functions. This cleans up type systems to be more pluggable. Prior to this we had issues: - Module, SymbolFile, and many others has "ClangASTContext &GetClangASTContext()" functions. All have been switched over to use "TypeSystem *GetTypeSystemForLanguage()" - Cleaned up any places that were using the GetClangASTContext() functions to use TypeSystem - Cleaned up Module so that it no longer has dedicated type system member variables: lldb::ClangASTContextUP m_ast; ///< The Clang AST context for this module. lldb::GoASTContextUP m_go_ast; ///< The Go AST context for this module. Now we have a type system map: typedef std::map<lldb::LanguageType, lldb::TypeSystemSP> TypeSystemMap; TypeSystemMap m_type_system_map; ///< A map of any type systems associated with this module - Many places in code were using ClangASTContext static functions to place with CompilerType objects and add modifiers (const, volatile, restrict) and to make typedefs, L and R value references and more. These have been made into CompilerType functions that are abstract: class CompilerType { ... //---------------------------------------------------------------------- // Return a new CompilerType that is a L value reference to this type if // this type is valid and the type system supports L value references, // else return an invalid type. //---------------------------------------------------------------------- CompilerType GetLValueReferenceType () const; //---------------------------------------------------------------------- // Return a new CompilerType that is a R value reference to this type if // this type is valid and the type system supports R value references, // else return an invalid type. //---------------------------------------------------------------------- CompilerType GetRValueReferenceType () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a const modifier to this type if // this type is valid and the type system supports const modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddConstModifier () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a volatile modifier to this type if // this type is valid and the type system supports volatile modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddVolatileModifier () const; //---------------------------------------------------------------------- // Return a new CompilerType adds a restrict modifier to this type if // this type is valid and the type system supports restrict modifiers, // else return an invalid type. //---------------------------------------------------------------------- CompilerType AddRestrictModifier () const; //---------------------------------------------------------------------- // Create a typedef to this type using "name" as the name of the typedef // this type is valid and the type system supports typedefs, else return // an invalid type. //---------------------------------------------------------------------- CompilerType CreateTypedef (const char *name, const CompilerDeclContext &decl_ctx) const; }; Other changes include: - Removed "CompilerType TypeSystem::GetIntTypeFromBitSize(...)" and CompilerType TypeSystem::GetFloatTypeFromBitSize(...) and replaced it with "CompilerType TypeSystem::GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, size_t bit_size);" - Fixed code in Type.h to not request the full type for a type for no good reason, just request the forward type and let the type expand as needed llvm-svn: 247953
2015-09-18 06:23:34 +08:00
return false;
}
} else if (arg_type == "void*") {
compiler_type =
type_system->GetBasicTypeFromAST(eBasicTypeVoid).GetPointerType();
} else if (arg_type == "char*") {
compiler_type =
type_system->GetBasicTypeFromAST(eBasicTypeChar).GetPointerType();
} else {
result.AppendErrorWithFormat("Invalid format: %s.\n", arg_entry.c_str());
result.SetStatus(eReturnStatusFailed);
return false;
}
value.SetCompilerType(compiler_type);
value_list.PushValue(value);
}
if (!abi->GetArgumentValues(*thread, value_list)) {
result.AppendError("Couldn't get argument values");
result.SetStatus(eReturnStatusFailed);
return false;
}
result.GetOutputStream().Printf("Arguments : \n");
for (auto entry : llvm::enumerate(args.entries())) {
result.GetOutputStream().Printf("%" PRIu64 " (%s): ", (uint64_t)entry.Index,
entry.Value.c_str());
value_list.GetValueAtIndex(entry.Index)->Dump(&result.GetOutputStream());
result.GetOutputStream().Printf("\n");
}
return result.Succeeded();
}