
LLDB currently attaches `AsmLabel`s to `FunctionDecl`s such that that the `IRExecutionUnit` can determine which mangled name to call (we can't rely on Clang deriving the correct mangled name to call because the debug-info AST doesn't contain all the info that would be encoded in the DWARF linkage names). However, we don't attach `AsmLabel`s for structors because they have multiple variants and thus it's not clear which mangled name to use. In the [RFC on fixing expression evaluation of abi-tagged structors](https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816) we discussed encoding the structor variant into the `AsmLabel`s. Specifically in [this thread](https://discourse.llvm.org/t/rfc-lldb-handling-abi-tagged-constructors-destructors-in-expression-evaluator/82816/7) we discussed that the contents of the `AsmLabel` are completely under LLDB's control and we could make use of it to uniquely identify a function by encoding the exact module and DIE that the function is associated with (mangled names need not be enough since two identical mangled symbols may live in different modules). So if we already have a custom `AsmLabel` format, we can encode the structor variant in a follow-up (the current idea is to append the structor variant as a suffix to our custom `AsmLabel` when Clang emits the mangled name into the JITted IR). Then we would just have to teach the `IRExecutionUnit` to pick the correct structor variant DIE during symbol resolution. The draft of this is available [here](https://github.com/llvm/llvm-project/pull/149827) This patch sets up the infrastructure for the custom `AsmLabel` format by encoding the module id, DIE id and mangled name in it. **Implementation** The flow is as follows: 1. Create the label in `DWARFASTParserClang`. The format is: `$__lldb_func:module_id:die_id:mangled_name` 2. When resolving external symbols in `IRExecutionUnit`, we parse this label and then do a lookup by DIE ID (or mangled name into the module if the encoded DIE is a declaration). Depends on https://github.com/llvm/llvm-project/pull/151355
123 lines
3.9 KiB
C++
123 lines
3.9 KiB
C++
//===-- ExpressionTest.cpp ------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "TestingSupport/TestUtilities.h"
|
|
#include "lldb/Expression/Expression.h"
|
|
#include "llvm/Testing/Support/Error.h"
|
|
|
|
using namespace lldb_private;
|
|
|
|
struct LabelTestCase {
|
|
llvm::StringRef encoded;
|
|
FunctionCallLabel label;
|
|
llvm::SmallVector<llvm::StringRef> error_pattern;
|
|
};
|
|
|
|
static LabelTestCase g_label_test_cases[] = {
|
|
// Failure modes
|
|
{"bar:0x0:0x0:_Z3foov",
|
|
{},
|
|
{"expected function call label prefix '$__lldb_func' but found 'bar' "
|
|
"instead."}},
|
|
{"$__lldb_func :0x0:0x0:_Z3foov",
|
|
{},
|
|
{"expected function call label prefix '$__lldb_func' but found "
|
|
"'$__lldb_func ' instead."}},
|
|
{"$__lldb_funcc:0x0:0x0:_Z3foov",
|
|
{},
|
|
{"expected function call label prefix '$__lldb_func' but found "
|
|
"'$__lldb_funcc' instead."}},
|
|
{"", {}, {"malformed function call label."}},
|
|
{"foo", {}, {"malformed function call label."}},
|
|
{"$__lldb_func", {}, {"malformed function call label."}},
|
|
{"$__lldb_func:", {}, {"malformed function call label."}},
|
|
{"$__lldb_func:0x0:0x0", {}, {"malformed function call label."}},
|
|
{"$__lldb_func:abc:0x0:_Z3foov",
|
|
{},
|
|
{"failed to parse module ID from 'abc'."}},
|
|
{"$__lldb_func:-1:0x0:_Z3foov",
|
|
{},
|
|
{"failed to parse module ID from '-1'."}},
|
|
{"$__lldb_func:0x0invalid:0x0:_Z3foov",
|
|
{},
|
|
{"failed to parse module ID from '0x0invalid'."}},
|
|
{"$__lldb_func:0x0 :0x0:_Z3foov",
|
|
{},
|
|
{"failed to parse module ID from '0x0 '."}},
|
|
{"$__lldb_func:0x0:abc:_Z3foov",
|
|
{},
|
|
{"failed to parse symbol ID from 'abc'."}},
|
|
{"$__lldb_func:0x5:-1:_Z3foov",
|
|
{},
|
|
{"failed to parse symbol ID from '-1'."}},
|
|
{"$__lldb_func:0x5:0x0invalid:_Z3foov",
|
|
{},
|
|
{"failed to parse symbol ID from '0x0invalid'."}},
|
|
{"$__lldb_func:0x5:0x0 :_Z3foov",
|
|
{},
|
|
{"failed to parse symbol ID from '0x0 '."}},
|
|
{"$__lldb_func:0x0:0x0:_Z3foov",
|
|
{
|
|
/*.module_id=*/0x0,
|
|
/*.symbol_id=*/0x0,
|
|
/*.lookup_name=*/"_Z3foov",
|
|
},
|
|
{}},
|
|
{"$__lldb_func:0x0:0x0:abc:def:::a",
|
|
{
|
|
/*.module_id=*/0x0,
|
|
/*.symbol_id=*/0x0,
|
|
/*.lookup_name=*/"abc:def:::a",
|
|
},
|
|
{}},
|
|
{"$__lldb_func:0xd2:0xf0:$__lldb_func",
|
|
{
|
|
/*.module_id=*/0xd2,
|
|
/*.symbol_id=*/0xf0,
|
|
/*.lookup_name=*/"$__lldb_func",
|
|
},
|
|
{}},
|
|
};
|
|
|
|
struct ExpressionTestFixture : public testing::TestWithParam<LabelTestCase> {};
|
|
|
|
TEST_P(ExpressionTestFixture, FunctionCallLabel) {
|
|
const auto &[encoded, label, errors] = GetParam();
|
|
|
|
auto decoded_or_err = FunctionCallLabel::fromString(encoded);
|
|
if (!errors.empty()) {
|
|
EXPECT_THAT_EXPECTED(
|
|
decoded_or_err,
|
|
llvm::FailedWithMessageArray(testing::ElementsAreArray(errors)));
|
|
return;
|
|
}
|
|
|
|
EXPECT_THAT_EXPECTED(decoded_or_err, llvm::Succeeded());
|
|
|
|
auto label_str = label.toString();
|
|
EXPECT_EQ(decoded_or_err->toString(), encoded);
|
|
EXPECT_EQ(label_str, encoded);
|
|
|
|
EXPECT_EQ(decoded_or_err->module_id, label.module_id);
|
|
EXPECT_EQ(decoded_or_err->symbol_id, label.symbol_id);
|
|
EXPECT_EQ(decoded_or_err->lookup_name, label.lookup_name);
|
|
|
|
auto roundtrip_or_err = FunctionCallLabel::fromString(label_str);
|
|
EXPECT_THAT_EXPECTED(roundtrip_or_err, llvm::Succeeded());
|
|
|
|
EXPECT_EQ(roundtrip_or_err->module_id, label.module_id);
|
|
EXPECT_EQ(roundtrip_or_err->symbol_id, label.symbol_id);
|
|
EXPECT_EQ(roundtrip_or_err->lookup_name, label.lookup_name);
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(FunctionCallLabelTest, ExpressionTestFixture,
|
|
testing::ValuesIn(g_label_test_cases));
|