Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb] add stop-at-user-entry option to process launch #67019

Merged
merged 1 commit into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lldb/include/lldb/Target/Language.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ class Language : public PluginInterface {

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;
Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/Target/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,8 @@ class Target : public std::enable_shared_from_this<Target>,

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,
Expand Down
8 changes: 5 additions & 3 deletions lldb/source/Commands/CommandOptionsProcessLaunch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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() =
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Commands/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">,
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ class CPlusPlusLanguage : public Language {
return lldb::eLanguageTypeC_plus_plus;
}

llvm::StringRef GetUserEntryPointName() const override { return "main"; }

std::unique_ptr<TypeScavenger> GetTypeScavenger() override;
lldb::TypeCategoryImplSP GetFormatters() override;

Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Plugins/Language/ObjC/ObjCLanguage.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ class ObjCLanguage : public Language {
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:]"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class ObjCPlusPlusLanguage : public Language {
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;
Expand Down
39 changes: 39 additions & 0 deletions lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
junior-jl marked this conversation as resolved.
Show resolved Hide resolved
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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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