mirror of
https://github.com/intel/llvm.git
synced 2026-01-14 11:57:39 +08:00
[lldb] add stop-at-user-entry option to process launch (#67019)
## Description This pull request adds a new `stop-at-user-entry` option to LLDB `process launch` command, allowing users to launch a process and pause execution at the entry point of the program (for C-based languages, `main` function). ## Motivation This option provides a convenient way to begin debugging a program by launching it and breaking at the desired entry point. ## Changes Made - Added `stop-at-user-entry` option to `Options.td` and the corresponding case in `CommandOptionsProcessLaunch.cpp` (short option is 'm') - Implemented `GetUserEntryPointName` method in the Language plugins available at the moment. - Declared the `CreateBreakpointAtUserEntry` method in the Target API. - Create Shell test for the command `command-process-launch-user-entry.test`. ## Usage `process launch --stop-at-user-entry` or `process launch -m` launches the process and pauses execution at the entry point of the program.
This commit is contained in:
@@ -160,6 +160,10 @@ public:
|
||||
|
||||
virtual lldb::LanguageType GetLanguageType() const = 0;
|
||||
|
||||
// Implement this function to return the user-defined entry point name
|
||||
// for the language.
|
||||
virtual llvm::StringRef GetUserEntryPointName() const { return {}; }
|
||||
|
||||
virtual bool IsTopLevelFunction(Function &function);
|
||||
|
||||
virtual bool IsSourceFile(llvm::StringRef file_path) const = 0;
|
||||
|
||||
@@ -654,6 +654,8 @@ public:
|
||||
|
||||
lldb::BreakpointSP GetBreakpointByID(lldb::break_id_t break_id);
|
||||
|
||||
lldb::BreakpointSP CreateBreakpointAtUserEntry(Status &error);
|
||||
|
||||
// Use this to create a file and line breakpoint to a given module or all
|
||||
// module it is nullptr
|
||||
lldb::BreakpointSP CreateBreakpoint(const FileSpecList *containingModules,
|
||||
|
||||
@@ -34,11 +34,15 @@ Status CommandOptionsProcessLaunch::SetOptionValue(
|
||||
Status error;
|
||||
const int short_option = g_process_launch_options[option_idx].short_option;
|
||||
|
||||
TargetSP target_sp =
|
||||
execution_context ? execution_context->GetTargetSP() : TargetSP();
|
||||
switch (short_option) {
|
||||
case 's': // Stop at program entry point
|
||||
launch_info.GetFlags().Set(eLaunchFlagStopAtEntry);
|
||||
break;
|
||||
|
||||
case 'm': // Stop at user entry point
|
||||
target_sp->CreateBreakpointAtUserEntry(error);
|
||||
break;
|
||||
case 'i': // STDIN for read only
|
||||
{
|
||||
FileAction action;
|
||||
@@ -89,8 +93,6 @@ Status CommandOptionsProcessLaunch::SetOptionValue(
|
||||
break;
|
||||
|
||||
case 'a': {
|
||||
TargetSP target_sp =
|
||||
execution_context ? execution_context->GetTargetSP() : TargetSP();
|
||||
PlatformSP platform_sp =
|
||||
target_sp ? target_sp->GetPlatform() : PlatformSP();
|
||||
launch_info.GetArchitecture() =
|
||||
|
||||
@@ -675,6 +675,10 @@ let Command = "platform shell" in {
|
||||
let Command = "process launch" in {
|
||||
def process_launch_stop_at_entry : Option<"stop-at-entry", "s">,
|
||||
Desc<"Stop at the entry point of the program when launching a process.">;
|
||||
def process_launch_stop_at_user_entry : Option<"stop-at-user-entry", "m">,
|
||||
Desc<"Stop at the user entry point when launching a process. For C based "
|
||||
"languages this will be the 'main' function, but this might differ for "
|
||||
"other languages.">;
|
||||
def process_launch_disable_aslr : Option<"disable-aslr", "A">, Arg<"Boolean">,
|
||||
Desc<"Set whether to disable address space layout randomization when launching a process.">;
|
||||
def process_launch_plugin : Option<"plugin", "P">, Arg<"Plugin">,
|
||||
|
||||
@@ -103,6 +103,8 @@ public:
|
||||
return lldb::eLanguageTypeC_plus_plus;
|
||||
}
|
||||
|
||||
llvm::StringRef GetUserEntryPointName() const override { return "main"; }
|
||||
|
||||
std::unique_ptr<TypeScavenger> GetTypeScavenger() override;
|
||||
lldb::TypeCategoryImplSP GetFormatters() override;
|
||||
|
||||
|
||||
@@ -127,6 +127,8 @@ public:
|
||||
return lldb::eLanguageTypeObjC;
|
||||
}
|
||||
|
||||
llvm::StringRef GetUserEntryPointName() const override { return "main"; }
|
||||
|
||||
// Get all possible names for a method. Examples:
|
||||
// If method_name is "+[NSString(my_additions) myStringWithCString:]"
|
||||
// variant_names[0] => "+[NSString myStringWithCString:]"
|
||||
|
||||
@@ -27,6 +27,8 @@ public:
|
||||
return lldb::eLanguageTypeObjC_plus_plus;
|
||||
}
|
||||
|
||||
llvm::StringRef GetUserEntryPointName() const override { return "main"; }
|
||||
|
||||
llvm::StringRef GetNilReferenceSummaryString() override { return "nil"; }
|
||||
|
||||
bool IsSourceFile(llvm::StringRef file_path) const override;
|
||||
|
||||
@@ -335,6 +335,45 @@ BreakpointSP Target::GetBreakpointByID(break_id_t break_id) {
|
||||
return bp_sp;
|
||||
}
|
||||
|
||||
lldb::BreakpointSP
|
||||
lldb_private::Target::CreateBreakpointAtUserEntry(Status &error) {
|
||||
ModuleSP main_module_sp = GetExecutableModule();
|
||||
FileSpecList shared_lib_filter;
|
||||
shared_lib_filter.Append(main_module_sp->GetFileSpec());
|
||||
llvm::SetVector<std::string, std::vector<std::string>,
|
||||
std::unordered_set<std::string>>
|
||||
entryPointNamesSet;
|
||||
for (LanguageType lang_type : Language::GetSupportedLanguages()) {
|
||||
Language *lang = Language::FindPlugin(lang_type);
|
||||
if (!lang) {
|
||||
error.SetErrorString("Language not found\n");
|
||||
return lldb::BreakpointSP();
|
||||
}
|
||||
std::string entryPointName = lang->GetUserEntryPointName().str();
|
||||
if (!entryPointName.empty())
|
||||
entryPointNamesSet.insert(entryPointName);
|
||||
}
|
||||
if (entryPointNamesSet.empty()) {
|
||||
error.SetErrorString("No entry point name found\n");
|
||||
return lldb::BreakpointSP();
|
||||
}
|
||||
BreakpointSP bp_sp = CreateBreakpoint(
|
||||
&shared_lib_filter,
|
||||
/*containingSourceFiles=*/nullptr, entryPointNamesSet.takeVector(),
|
||||
/*func_name_type_mask=*/eFunctionNameTypeFull,
|
||||
/*language=*/eLanguageTypeUnknown,
|
||||
/*offset=*/0,
|
||||
/*skip_prologue=*/eLazyBoolNo,
|
||||
/*internal=*/false,
|
||||
/*hardware=*/false);
|
||||
if (!bp_sp) {
|
||||
error.SetErrorString("Breakpoint creation failed.\n");
|
||||
return lldb::BreakpointSP();
|
||||
}
|
||||
bp_sp->SetOneShot(true);
|
||||
return bp_sp;
|
||||
}
|
||||
|
||||
BreakpointSP Target::CreateSourceRegexBreakpoint(
|
||||
const FileSpecList *containingModules,
|
||||
const FileSpecList *source_file_spec_list,
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# RUN: %clang_host -g %S/Inputs/main.c -o %t
|
||||
# RUN: %lldb %t -s %s -o exit | FileCheck %s
|
||||
|
||||
process launch -m
|
||||
# CHECK-LABEL: process launch -m
|
||||
# CHECK: Process {{.*}} stopped
|
||||
# CHECK: stop reason = one-shot breakpoint 1
|
||||
# CHECK: frame #0: {{.*}}`main at main.c
|
||||
Reference in New Issue
Block a user