Skip to content

Commit f487d1f

Browse files
committed
[lldb][Mangled] Retrieve and cache demangled name info
Uses the `TrackingOutputBuffer` to populate the new member `Mangled::m_demangled_info`. `m_demangled_info` is lazily popluated by `GetDemangledInfo`. To ensure `m_demangled` and `m_demangled_info` are in-sync we clear `m_demangled_info` anytime `m_demangled` is set/cleared. TODO: test
1 parent f50165c commit f487d1f

File tree

5 files changed

+143
-13
lines changed

5 files changed

+143
-13
lines changed

lldb/include/lldb/Core/Mangled.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
#ifndef LLDB_CORE_MANGLED_H
1010
#define LLDB_CORE_MANGLED_H
1111

12+
#include "lldb/Core/DemangledNameInfo.h"
13+
#include "lldb/Utility/ConstString.h"
1214
#include "lldb/lldb-enumerations.h"
1315
#include "lldb/lldb-forward.h"
1416
#include "lldb/lldb-types.h"
15-
#include "lldb/Utility/ConstString.h"
1617
#include "llvm/ADT/StringRef.h"
1718

1819
#include <cstddef>
@@ -134,9 +135,15 @@ class Mangled {
134135
/// A const reference to the display demangled name string object.
135136
ConstString GetDisplayDemangledName() const;
136137

137-
void SetDemangledName(ConstString name) { m_demangled = name; }
138+
void SetDemangledName(ConstString name) {
139+
m_demangled = name;
140+
m_demangled_info.reset();
141+
}
138142

139-
void SetMangledName(ConstString name) { m_mangled = name; }
143+
void SetMangledName(ConstString name) {
144+
m_mangled = name;
145+
m_demangled_info.reset();
146+
}
140147

141148
/// Mangled name get accessor.
142149
///
@@ -275,6 +282,9 @@ class Mangled {
275282
/// table offsets in the cache data.
276283
void Encode(DataEncoder &encoder, ConstStringTable &strtab) const;
277284

285+
/// Retrieve \c DemangledNameInfo of the demangled name held by this object.
286+
const std::optional<DemangledNameInfo> &GetDemangledInfo() const;
287+
278288
private:
279289
/// If \c force is \c false, this function will re-use the previously
280290
/// demangled name (if any). If \c force is \c true (or the mangled name
@@ -288,6 +298,10 @@ class Mangled {
288298
/// Mutable so we can get it on demand with
289299
/// a const version of this object.
290300
mutable ConstString m_demangled;
301+
302+
/// If available, holds information about where in \c m_demangled certain
303+
/// parts of the name (e.g., basename, arguments, etc.) begin and end.
304+
mutable std::optional<DemangledNameInfo> m_demangled_info = std::nullopt;
291305
};
292306

293307
Stream &operator<<(Stream &s, const Mangled &obj);

lldb/source/Core/Mangled.cpp

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "lldb/Core/Mangled.h"
1010

1111
#include "lldb/Core/DataFileCache.h"
12+
#include "lldb/Core/DemangledNameInfo.h"
1213
#include "lldb/Core/RichManglingContext.h"
1314
#include "lldb/Target/Language.h"
1415
#include "lldb/Utility/ConstString.h"
@@ -111,6 +112,7 @@ Mangled::operator bool() const { return m_mangled || m_demangled; }
111112
void Mangled::Clear() {
112113
m_mangled.Clear();
113114
m_demangled.Clear();
115+
m_demangled_info.reset();
114116
}
115117

116118
// Compare the string values.
@@ -124,13 +126,16 @@ void Mangled::SetValue(ConstString name) {
124126
if (cstring_is_mangled(name.GetStringRef())) {
125127
m_demangled.Clear();
126128
m_mangled = name;
129+
m_demangled_info.reset();
127130
} else {
128131
m_demangled = name;
129132
m_mangled.Clear();
133+
m_demangled_info.reset();
130134
}
131135
} else {
132136
m_demangled.Clear();
133137
m_mangled.Clear();
138+
m_demangled_info.reset();
134139
}
135140
}
136141

@@ -152,20 +157,26 @@ static char *GetMSVCDemangledStr(llvm::StringRef M) {
152157
return demangled_cstr;
153158
}
154159

155-
static char *GetItaniumDemangledStr(const char *M) {
160+
static std::pair<char *, DemangledNameInfo>
161+
GetItaniumDemangledStr(const char *M) {
156162
char *demangled_cstr = nullptr;
157163

164+
DemangledNameInfo info;
158165
llvm::ItaniumPartialDemangler ipd;
159166
bool err = ipd.partialDemangle(M);
160167
if (!err) {
161-
// Default buffer and size (will realloc in case it's too small).
168+
// Default buffer and size (OutputBuffer will realloc in case it's too
169+
// small).
162170
size_t demangled_size = 80;
163-
demangled_cstr = static_cast<char *>(std::malloc(demangled_size));
164-
demangled_cstr = ipd.finishDemangle(demangled_cstr, &demangled_size);
171+
demangled_cstr = static_cast<char *>(std::malloc(80));
172+
173+
TrackingOutputBuffer OB(demangled_cstr, demangled_size);
174+
demangled_cstr = ipd.finishDemangle(&OB);
175+
info = std::move(OB.NameInfo);
165176

166177
assert(demangled_cstr &&
167178
"finishDemangle must always succeed if partialDemangle did");
168-
assert(demangled_cstr[demangled_size - 1] == '\0' &&
179+
assert(demangled_cstr[OB.getCurrentPosition() - 1] == '\0' &&
169180
"Expected demangled_size to return length including trailing null");
170181
}
171182

@@ -174,9 +185,14 @@ static char *GetItaniumDemangledStr(const char *M) {
174185
LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr);
175186
else
176187
LLDB_LOGF(log, "demangled itanium: %s -> error: failed to demangle", M);
188+
189+
if (!info.hasBasename())
190+
LLDB_LOGF(log,
191+
"demangled itanium: %s -> error: failed to retrieve name info",
192+
M);
177193
}
178194

179-
return demangled_cstr;
195+
return {demangled_cstr, std::move(info)};
180196
}
181197

182198
static char *GetRustV0DemangledStr(llvm::StringRef M) {
@@ -269,6 +285,13 @@ ConstString Mangled::GetDemangledName() const {
269285
return GetDemangledNameImpl(/*force=*/false);
270286
}
271287

288+
std::optional<DemangledNameInfo> const &Mangled::GetDemangledInfo() const {
289+
if (!m_demangled_info)
290+
GetDemangledNameImpl(/*force=*/true);
291+
292+
return m_demangled_info;
293+
}
294+
272295
// Generate the demangled name on demand using this accessor. Code in this
273296
// class will need to use this accessor if it wishes to decode the demangled
274297
// name. The result is cached and will be kept until a new string value is
@@ -293,7 +316,10 @@ ConstString Mangled::GetDemangledNameImpl(bool force) const {
293316
demangled_name = GetMSVCDemangledStr(m_mangled);
294317
break;
295318
case eManglingSchemeItanium: {
296-
demangled_name = GetItaniumDemangledStr(m_mangled.GetCString());
319+
std::pair<char *, DemangledNameInfo> demangled =
320+
GetItaniumDemangledStr(m_mangled.GetCString());
321+
demangled_name = demangled.first;
322+
m_demangled_info.emplace(std::move(demangled.second));
297323
break;
298324
}
299325
case eManglingSchemeRustV0:
@@ -452,6 +478,7 @@ bool Mangled::Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,
452478
const StringTableReader &strtab) {
453479
m_mangled.Clear();
454480
m_demangled.Clear();
481+
m_demangled_info.reset();
455482
MangledEncoding encoding = (MangledEncoding)data.GetU8(offset_ptr);
456483
switch (encoding) {
457484
case Empty:

lldb/unittests/Core/MangledTest.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,77 @@ TEST(MangledTest, NameIndexes_FindFunctionSymbols) {
321321
EXPECT_EQ(0, Count("undemangable", eFunctionNameTypeMethod));
322322
}
323323

324+
TEST(MangledTest, DemangledNameInfo_SetMangledResets) {
325+
Mangled mangled;
326+
EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
327+
328+
mangled.SetMangledName(ConstString("_Z3foov"));
329+
ASSERT_TRUE(mangled);
330+
331+
auto info1 = mangled.GetDemangledInfo();
332+
EXPECT_NE(info1, std::nullopt);
333+
EXPECT_TRUE(info1->hasBasename());
334+
335+
mangled.SetMangledName(ConstString("_Z4funcv"));
336+
337+
// Should have re-calculated demangled-info since mangled name changed.
338+
auto info2 = mangled.GetDemangledInfo();
339+
ASSERT_NE(info2, std::nullopt);
340+
EXPECT_TRUE(info2->hasBasename());
341+
342+
EXPECT_NE(info1.value(), info2.value());
343+
EXPECT_EQ(mangled.GetDemangledName(), "func()");
344+
}
345+
346+
TEST(MangledTest, DemangledNameInfo_SetDemangledResets) {
347+
Mangled mangled("_Z3foov");
348+
ASSERT_TRUE(mangled);
349+
350+
mangled.SetDemangledName(ConstString(""));
351+
352+
// Mangled name hasn't changed, so GetDemangledInfo causes re-demangling
353+
// of previously set mangled name.
354+
EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt);
355+
EXPECT_EQ(mangled.GetDemangledName(), "foo()");
356+
}
357+
358+
TEST(MangledTest, DemangledNameInfo_Clear) {
359+
Mangled mangled("_Z3foov");
360+
ASSERT_TRUE(mangled);
361+
EXPECT_NE(mangled.GetDemangledInfo(), std::nullopt);
362+
363+
mangled.Clear();
364+
365+
EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
366+
}
367+
368+
TEST(MangledTest, DemangledNameInfo_SetValue) {
369+
Mangled mangled("_Z4funcv");
370+
ASSERT_TRUE(mangled);
371+
372+
auto demangled_func = mangled.GetDemangledInfo();
373+
374+
// SetValue(mangled) resets demangled-info
375+
mangled.SetValue(ConstString("_Z3foov"));
376+
auto demangled_foo = mangled.GetDemangledInfo();
377+
EXPECT_NE(demangled_foo, std::nullopt);
378+
EXPECT_NE(demangled_foo, demangled_func);
379+
380+
// SetValue(demangled) resets demangled-info
381+
mangled.SetValue(ConstString("_Z4funcv"));
382+
EXPECT_EQ(mangled.GetDemangledInfo(), demangled_func);
383+
384+
// SetValue(empty) resets demangled-info
385+
mangled.SetValue(ConstString());
386+
EXPECT_EQ(mangled.GetDemangledInfo(), std::nullopt);
387+
388+
// Demangling invalid mangled name will set demangled-info
389+
// (without a valid basename).
390+
mangled.SetValue(ConstString("_Zinvalid"));
391+
ASSERT_NE(mangled.GetDemangledInfo(), std::nullopt);
392+
EXPECT_FALSE(mangled.GetDemangledInfo()->hasBasename());
393+
}
394+
324395
struct DemanglingPartsTestCase {
325396
const char *mangled;
326397
DemangledNameInfo expected_info;

llvm/include/llvm/Demangle/Demangle.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ struct ItaniumPartialDemangler {
9393
/// second and third parameters to __cxa_demangle.
9494
char *finishDemangle(char *Buf, size_t *N) const;
9595

96+
/// See \ref finishDemangle
97+
///
98+
/// \param[in] OB A llvm::itanium_demangle::OutputBuffer that the demangled
99+
/// name will be printed into.
100+
///
101+
char *finishDemangle(void *OB) const;
102+
96103
/// Get the base name of a function. This doesn't include trailing template
97104
/// arguments, ie for "a::b<int>" this function returns "b".
98105
char *getFunctionBaseName(char *Buf, size_t *N) const;

llvm/lib/Demangle/ItaniumDemangle.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -411,16 +411,19 @@ bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
411411
RootNode = Parser->parse();
412412
return RootNode == nullptr;
413413
}
414-
415-
static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
416-
OutputBuffer OB(Buf, N);
414+
static char *printNode(const Node *RootNode, OutputBuffer &OB, size_t *N) {
417415
RootNode->print(OB);
418416
OB += '\0';
419417
if (N != nullptr)
420418
*N = OB.getCurrentPosition();
421419
return OB.getBuffer();
422420
}
423421

422+
static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
423+
OutputBuffer OB(Buf, N);
424+
return printNode(RootNode, OB, N);
425+
}
426+
424427
char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
425428
if (!isFunction())
426429
return nullptr;
@@ -540,6 +543,14 @@ char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
540543
return printNode(static_cast<Node *>(RootNode), Buf, N);
541544
}
542545

546+
char *ItaniumPartialDemangler::finishDemangle(void *OB) const {
547+
assert(RootNode != nullptr && "must call partialDemangle()");
548+
assert(OB != nullptr && "valid OutputBuffer argument required");
549+
return printNode(static_cast<Node *>(RootNode),
550+
*static_cast<OutputBuffer *>(OB),
551+
/*N=*/nullptr);
552+
}
553+
543554
bool ItaniumPartialDemangler::hasFunctionQualifiers() const {
544555
assert(RootNode != nullptr && "must call partialDemangle()");
545556
if (!isFunction())

0 commit comments

Comments
 (0)