Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
6ad1930
[lldb][NFC] Use IterationAction for ModuleList::ForEach callbacks (#1…
Michael137 Jul 28, 2025
aba003f
[lldb][TypeSystemClang] Make AsmLabel parameter a llvm::StringRef (#1…
Michael137 Jul 31, 2025
261a9f2
[lldb][DWARFIndex][NFC] Change GetFunctions return type to IterationA…
Michael137 Jul 31, 2025
5f91976
[lldb][Expression] Encode Module and DIE UIDs into function AsmLabels…
Michael137 Aug 1, 2025
f379f41
[lldb][test] Fix expected mangling for AsmLabel_CtorDtor test on Windows
Michael137 Aug 1, 2025
b2fbf94
[lldb][test] Skip TestExprDefinitionInDylib on Windows
Michael137 Aug 1, 2025
c30b5a5
[lldb][test] Fix expected mangling for AsmLabel_CtorDtor test on Wind…
Michael137 Aug 1, 2025
c9d688e
[lldb][test] Un-XFAIL tail_call_frames tests on Linux arm/arm64
Michael137 Aug 1, 2025
330359f
[lldb][DWARFIndex][NFC] Change GetNamespace/GetGlobalVariables APIs t…
Michael137 Aug 2, 2025
0cfd822
[clang][Attr] Remove 'literal label' form of AsmLabelAttr (#151858)
Michael137 Aug 4, 2025
d9fce4f
[lldb][DWARFIndex] Adapt DWARFIndex ObjC APIs to IterationAction (#15…
Michael137 Aug 4, 2025
99282da
[lldb][DWARFIndex] Adapt DWARFIndex GetTypes APIs to IterationAction …
Michael137 Aug 4, 2025
7a6dc77
[lldb][DWARFIndex] Adapt DWARFIndex DIERefCallback to IterationAction…
Michael137 Aug 4, 2025
f36de27
[lldb][DWARFIndex] Adapt DebugNamesDWARFIndex::ProcessEntry to Iterat…
Michael137 Aug 4, 2025
0acc6c3
[lldb][DWARFIndex][NFC] Remove DWARFIndex::IterationActionAdaptor
Michael137 Aug 4, 2025
a62a8d8
[lldb][SymbolFileDWARF][NFC] Add FindFunctionDefinition helper (#152733)
Michael137 Aug 8, 2025
6cf2732
[lldb][Swift][NFC] Adapt Swift plugin callables to IterationAction
Michael137 Sep 2, 2025
3e1d574
[lldb][Expression][NFC] Make LoadAddressResolver::m_target a referenc…
Michael137 Jul 18, 2025
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
17 changes: 4 additions & 13 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1084,22 +1084,13 @@ def AVRSignal : InheritableAttr, TargetSpecificAttr<TargetAVR> {
def AsmLabel : InheritableAttr {
let Spellings = [CustomKeyword<"asm">, CustomKeyword<"__asm__">];
let Args = [
// Label specifies the mangled name for the decl.
StringArgument<"Label">,

// IsLiteralLabel specifies whether the label is literal (i.e. suppresses
// the global C symbol prefix) or not. If not, the mangle-suppression prefix
// ('\01') is omitted from the decl name at the LLVM IR level.
//
// Non-literal labels are used by some external AST sources like LLDB.
BoolArgument<"IsLiteralLabel", /*optional=*/0, /*fake=*/1>
];
// Label specifies the mangled name for the decl.
StringArgument<"Label">, ];
let SemaHandler = 0;
let Documentation = [AsmLabelDocs];
let AdditionalMembers =
[{
let AdditionalMembers = [{
bool isEquivalent(AsmLabelAttr *Other) const {
return getLabel() == Other->getLabel() && getIsLiteralLabel() == Other->getIsLiteralLabel();
return getLabel() == Other->getLabel();
}
}];
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,9 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
// If we have an asm name, then we use it as the mangling.

// If the label isn't literal, or if this is an alias for an LLVM intrinsic,
// If the label is an alias for an LLVM intrinsic,
// do not add a "\01" prefix.
if (!ALA->getIsLiteralLabel() || ALA->getLabel().starts_with("llvm.")) {
if (ALA->getLabel().starts_with("llvm.")) {
Out << ALA->getLabel();
return;
}
Expand Down
13 changes: 5 additions & 8 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8951,9 +8951,7 @@ NamedDecl *Sema::ActOnVariableDeclarator(
}
}

NewVD->addAttr(AsmLabelAttr::Create(Context, Label,
/*IsLiteralLabel=*/true,
SE->getStrTokenLoc(0)));
NewVD->addAttr(AsmLabelAttr::Create(Context, Label, SE->getStrTokenLoc(0)));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier());
Expand Down Expand Up @@ -11254,9 +11252,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (Expr *E = D.getAsmLabel()) {
// The parser guarantees this is a string.
StringLiteral *SE = cast<StringLiteral>(E);
NewFD->addAttr(AsmLabelAttr::Create(Context, SE->getString(),
/*IsLiteralLabel=*/true,
SE->getStrTokenLoc(0)));
NewFD->addAttr(
AsmLabelAttr::Create(Context, SE->getString(), SE->getStrTokenLoc(0)));
} else if (!ExtnameUndeclaredIdentifiers.empty()) {
llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I =
ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier());
Expand Down Expand Up @@ -21737,8 +21734,8 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name,
LookupOrdinaryName);
AttributeCommonInfo Info(AliasName, SourceRange(AliasNameLoc),
AttributeCommonInfo::Form::Pragma());
AsmLabelAttr *Attr = AsmLabelAttr::CreateImplicit(
Context, AliasName->getName(), /*IsLiteralLabel=*/true, Info);
AsmLabelAttr *Attr =
AsmLabelAttr::CreateImplicit(Context, AliasName->getName(), Info);

// If a declaration that:
// 1) declares a function or a variable
Expand Down
9 changes: 1 addition & 8 deletions clang/unittests/AST/DeclTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ TEST(Decl, AsmLabelAttr) {
StringRef Code = R"(
struct S {
void f() {}
void g() {}
};
)";
auto AST =
Expand All @@ -144,26 +143,20 @@ TEST(Decl, AsmLabelAttr) {
const auto *DeclS =
selectFirst<CXXRecordDecl>("d", match(cxxRecordDecl().bind("d"), Ctx));
NamedDecl *DeclF = *DeclS->method_begin();
NamedDecl *DeclG = *(++DeclS->method_begin());

// Attach asm labels to the decls: one literal, and one not.
DeclF->addAttr(AsmLabelAttr::Create(Ctx, "foo", /*LiteralLabel=*/true));
DeclG->addAttr(AsmLabelAttr::Create(Ctx, "goo", /*LiteralLabel=*/false));
DeclF->addAttr(AsmLabelAttr::Create(Ctx, "foo"));

// Mangle the decl names.
std::string MangleF, MangleG;
std::unique_ptr<ItaniumMangleContext> MC(
ItaniumMangleContext::create(Ctx, Diags));
{
llvm::raw_string_ostream OS_F(MangleF);
llvm::raw_string_ostream OS_G(MangleG);
MC->mangleName(DeclF, OS_F);
MC->mangleName(DeclG, OS_G);
}

ASSERT_EQ(MangleF, "\x01"
"foo");
ASSERT_EQ(MangleG, "goo");
}

TEST(Decl, MangleDependentSizedArray) {
Expand Down
3 changes: 2 additions & 1 deletion lldb/include/lldb/Core/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ struct ModuleFunctionSearchOptions {
///
/// The module will parse more detailed information as more queries are made.
class Module : public std::enable_shared_from_this<Module>,
public SymbolContextScope {
public SymbolContextScope,
public UserID {
public:
class LookupInfo;
// Static functions that can track the lifetime of module objects. This is
Expand Down
14 changes: 12 additions & 2 deletions lldb/include/lldb/Core/ModuleList.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "lldb/Utility/Status.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private-enumerations.h"
#include "lldb/lldb-types.h"

#include "llvm/ADT/DenseSet.h"
Expand Down Expand Up @@ -374,6 +375,14 @@ class ModuleList {
// UUID values is very efficient and accurate.
lldb::ModuleSP FindModule(const UUID &uuid) const;

/// Find a module by LLDB-specific unique identifier.
///
/// \param[in] uid The UID of the module assigned to it on construction.
///
/// \returns ModuleSP of module with \c uid. Returns nullptr if no such
/// module could be found.
lldb::ModuleSP FindModule(lldb::user_id_t uid) const;

/// Finds the first module whose file specification matches \a module_spec.
lldb::ModuleSP FindFirstModule(const ModuleSpec &module_spec) const;

Expand Down Expand Up @@ -530,8 +539,9 @@ class ModuleList {
/// be non-null.
///
/// This function is thread-safe.
void ForEach(std::function<bool(const lldb::ModuleSP &module_sp)> const
&callback) const;
void
ForEach(std::function<IterationAction(const lldb::ModuleSP &module_sp)> const
&callback) const;

void ClearModuleDependentCaches();

Expand Down
57 changes: 57 additions & 0 deletions lldb/include/lldb/Expression/Expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <string>
#include <vector>

#include "llvm/Support/FormatProviders.h"

#include "lldb/Expression/ExpressionTypeSystemHelper.h"
#include "lldb/lldb-forward.h"
Expand Down Expand Up @@ -96,6 +97,62 @@ class Expression {
///invalid.
};

/// Holds parsed information about a function call label that
/// LLDB attaches as an AsmLabel to function AST nodes it parses
/// from debug-info.
///
/// The format being:
///
/// <prefix>:<module uid>:<symbol uid>:<name>
///
/// The label string needs to stay valid for the entire lifetime
/// of this object.
struct FunctionCallLabel {
/// Unique identifier of the lldb_private::Module
/// which contains the symbol identified by \c symbol_id.
lldb::user_id_t module_id;

/// Unique identifier of the function symbol on which to
/// perform the function call. For example, for DWARF this would
/// be the DIE UID.
lldb::user_id_t symbol_id;

/// Name to use when searching for the function symbol in
/// \c module_id. For most function calls this will be a
/// mangled name. In cases where a mangled name can't be used,
/// this will be the function name.
///
/// NOTE: kept as last element so we don't have to worry about
/// ':' in the mangled name when parsing the label.
llvm::StringRef lookup_name;

/// Decodes the specified function \c label into a \c FunctionCallLabel.
static llvm::Expected<FunctionCallLabel> fromString(llvm::StringRef label);

/// Encode this FunctionCallLabel into its string representation.
///
/// The representation roundtrips through \c fromString:
/// \code{.cpp}
/// llvm::StringRef encoded = "$__lldb_func:0x0:0x0:_Z3foov";
/// FunctionCallLabel label = *fromString(label);
///
/// assert (label.toString() == encoded);
/// assert (*fromString(label.toString()) == label);
/// \endcode
std::string toString() const;
};

/// LLDB attaches this prefix to mangled names of functions that get called
/// from JITted expressions.
inline constexpr llvm::StringRef FunctionCallLabelPrefix = "$__lldb_func";

} // namespace lldb_private

namespace llvm {
template <> struct format_provider<lldb_private::FunctionCallLabel> {
static void format(const lldb_private::FunctionCallLabel &label,
raw_ostream &OS, StringRef Style);
};
} // namespace llvm

#endif // LLDB_EXPRESSION_EXPRESSION_H
12 changes: 12 additions & 0 deletions lldb/include/lldb/Symbol/SymbolFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,18 @@ class SymbolFile : public PluginInterface {
GetMangledNamesForFunction(const std::string &scope_qualified_name,
std::vector<ConstString> &mangled_names);

/// Resolves the function corresponding to the specified LLDB function
/// call \c label.
///
/// \param[in] label The FunctionCallLabel to be resolved.
///
/// \returns An llvm::Error if the specified \c label couldn't be resolved.
/// Returns the resolved function (as a SymbolContext) otherwise.
virtual llvm::Expected<SymbolContext>
ResolveFunctionCallLabel(const FunctionCallLabel &label) {
return llvm::createStringError("Not implemented");
}

virtual void GetTypes(lldb_private::SymbolContextScope *sc_scope,
lldb::TypeClass type_mask,
lldb_private::TypeList &type_list) = 0;
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Commands/CommandCompletions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ void CommandCompletions::ModuleUUIDs(CommandInterpreter &interpreter,
lldb::eDescriptionLevelInitial);
request.TryCompleteCurrentArg(module->GetUUID().GetAsString(),
strm.GetString());
return true;
return IterationAction::Continue;
});
}

Expand Down
9 changes: 6 additions & 3 deletions lldb/source/Core/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,10 @@ Module *Module::GetAllocatedModuleAtIndex(size_t idx) {
return nullptr;
}

static std::atomic<lldb::user_id_t> g_unique_id = 1;

Module::Module(const ModuleSpec &module_spec)
: m_unwind_table(*this), m_file_has_changed(false),
: UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false),
m_first_file_changed_log(false) {
// Scope for locker below...
{
Expand Down Expand Up @@ -241,7 +243,8 @@ Module::Module(const ModuleSpec &module_spec)
Module::Module(const FileSpec &file_spec, const ArchSpec &arch,
ConstString object_name, lldb::offset_t object_offset,
const llvm::sys::TimePoint<> &object_mod_time)
: m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
: UserID(g_unique_id++),
m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
m_arch(arch), m_file(file_spec), m_object_name(object_name),
m_object_offset(object_offset), m_object_mod_time(object_mod_time),
m_unwind_table(*this), m_file_has_changed(false),
Expand All @@ -262,7 +265,7 @@ Module::Module(const FileSpec &file_spec, const ArchSpec &arch,
}

Module::Module()
: m_unwind_table(*this), m_file_has_changed(false),
: UserID(g_unique_id++), m_unwind_table(*this), m_file_has_changed(false),
m_first_file_changed_log(false) {
std::lock_guard<std::recursive_mutex> guard(
GetAllocationModuleCollectionMutex());
Expand Down
20 changes: 17 additions & 3 deletions lldb/source/Core/ModuleList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,20 @@ ModuleSP ModuleList::FindModule(const UUID &uuid) const {
return module_sp;
}

ModuleSP ModuleList::FindModule(lldb::user_id_t uid) const {
ModuleSP module_sp;
ForEach([&](const ModuleSP &m) {
if (m->GetID() == uid) {
module_sp = m;
return IterationAction::Stop;
}

return IterationAction::Continue;
});

return module_sp;
}

void ModuleList::FindTypes(Module *search_first, const TypeQuery &query,
TypeResults &results) const {
std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
Expand Down Expand Up @@ -1343,12 +1357,12 @@ bool ModuleList::LoadScriptingResourcesInTarget(Target *target,
}

void ModuleList::ForEach(
std::function<bool(const ModuleSP &module_sp)> const &callback) const {
std::function<IterationAction(const ModuleSP &module_sp)> const &callback)
const {
std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
for (const auto &module_sp : m_modules) {
assert(module_sp != nullptr);
// If the callback returns false, then stop iterating and break out
if (!callback(module_sp))
if (callback(module_sp) == IterationAction::Stop)
break;
}
}
Expand Down
49 changes: 49 additions & 0 deletions lldb/source/Expression/Expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/Target.h"

#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"

using namespace lldb_private;

Expression::Expression(Target &target)
Expand All @@ -26,3 +31,47 @@ Expression::Expression(ExecutionContextScope &exe_scope)
m_jit_end_addr(LLDB_INVALID_ADDRESS) {
assert(m_target_wp.lock());
}

llvm::Expected<FunctionCallLabel>
lldb_private::FunctionCallLabel::fromString(llvm::StringRef label) {
llvm::SmallVector<llvm::StringRef, 4> components;
label.split(components, ":", /*MaxSplit=*/3);

if (components.size() != 4)
return llvm::createStringError("malformed function call label.");

if (components[0] != FunctionCallLabelPrefix)
return llvm::createStringError(llvm::formatv(
"expected function call label prefix '{0}' but found '{1}' instead.",
FunctionCallLabelPrefix, components[0]));

llvm::StringRef module_label = components[1];
llvm::StringRef die_label = components[2];

lldb::user_id_t module_id = 0;
if (!llvm::to_integer(module_label, module_id))
return llvm::createStringError(
llvm::formatv("failed to parse module ID from '{0}'.", module_label));

lldb::user_id_t die_id;
if (!llvm::to_integer(die_label, die_id))
return llvm::createStringError(
llvm::formatv("failed to parse symbol ID from '{0}'.", die_label));

return FunctionCallLabel{/*.module_id=*/module_id,
/*.symbol_id=*/die_id,
/*.lookup_name=*/components[3]};
}

std::string lldb_private::FunctionCallLabel::toString() const {
return llvm::formatv("{0}:{1:x}:{2:x}:{3}", FunctionCallLabelPrefix,
module_id, symbol_id, lookup_name)
.str();
}

void llvm::format_provider<FunctionCallLabel>::format(
const FunctionCallLabel &label, raw_ostream &OS, StringRef Style) {
OS << llvm::formatv("FunctionCallLabel{ module_id: {0:x}, symbol_id: {1:x}, "
"lookup_name: {2} }",
label.module_id, label.symbol_id, label.lookup_name);
}
Loading