Skip to content

Commit 0c58497

Browse files
committed
Fix asan and tsan tests
Signed-off-by: Dom Del Nano <[email protected]>
1 parent 2014729 commit 0c58497

File tree

5 files changed

+141
-46
lines changed

5 files changed

+141
-46
lines changed

src/stirling/obj_tools/dwarf_reader.cc

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -92,28 +92,30 @@ StatusOr<std::unique_ptr<DwarfReader>> DwarfReader::CreateWithoutIndexing(
9292
auto dwarf_reader = std::unique_ptr<DwarfReader>(
9393
new DwarfReader(std::move(buffer), DWARFContext::create(*obj_file)));
9494

95-
PX_RETURN_IF_ERROR(dwarf_reader->DetectSourceLanguage());
96-
9795
return dwarf_reader;
9896
}
9997

10098
StatusOr<std::unique_ptr<DwarfReader>> DwarfReader::CreateIndexingAll(
10199
const std::filesystem::path& path) {
102100
PX_ASSIGN_OR_RETURN(auto dwarf_reader, CreateWithoutIndexing(path));
103101
dwarf_reader->IndexDIEs(std::nullopt);
102+
PX_RETURN_IF_ERROR(dwarf_reader->DetectSourceLanguage());
104103
return dwarf_reader;
105104
}
106105

107106
StatusOr<std::unique_ptr<DwarfReader>> DwarfReader::CreateWithSelectiveIndexing(
108107
const std::filesystem::path& path, const std::vector<SymbolSearchPattern>& symbol_patterns) {
109108
PX_ASSIGN_OR_RETURN(auto dwarf_reader, CreateWithoutIndexing(path));
110109
dwarf_reader->IndexDIEs(symbol_patterns);
110+
PX_RETURN_IF_ERROR(dwarf_reader->DetectSourceLanguage());
111111
return dwarf_reader;
112112
}
113113

114114
DwarfReader::DwarfReader(std::unique_ptr<llvm::MemoryBuffer> buffer,
115115
std::unique_ptr<llvm::DWARFContext> dwarf_context)
116-
: memory_buffer_(std::move(buffer)), dwarf_context_(std::move(dwarf_context)) {
116+
: is_multi_lang_(std::nullopt),
117+
memory_buffer_(std::move(buffer)),
118+
dwarf_context_(std::move(dwarf_context)) {
117119
// Only very first call will actually perform initialization.
118120
InitLLVMOnce();
119121
}
@@ -154,31 +156,60 @@ bool IsNamespace(llvm::dwarf::Tag tag) { return tag == llvm::dwarf::DW_TAG_names
154156

155157
} // namespace
156158

159+
StatusOr<std::pair<llvm::dwarf::SourceLanguage, std::string>>
160+
DwarfReader::DetectSourceLanguageFromCUDIE(const llvm::DWARFDie& unit_die) {
161+
if (unit_die.getTag() != llvm::dwarf::DW_TAG_compile_unit) {
162+
// Skip over DW_TAG_partial_unit, and potentially other tags.
163+
return error::NotFound("Expected DW_TAG_compile_unit, but got DW_TAG=$0 for unit DIE: $1",
164+
magic_enum::enum_name(unit_die.getTag()), Dump(unit_die));
165+
}
166+
const DWARFFormValue& producer_attr =
167+
GetAttribute(unit_die, llvm::dwarf::DW_AT_producer).ValueOr({});
168+
auto s = producer_attr.getAsCString();
169+
std::string compiler;
170+
#if LLVM_VERSION_MAJOR >= 14
171+
if (!s.takeError()) {
172+
compiler = s.get();
173+
}
174+
#else
175+
compiler = s.getValueOr("");
176+
#endif
177+
PX_ASSIGN_OR_RETURN(const DWARFFormValue& lang_attr,
178+
GetAttribute(unit_die, llvm::dwarf::DW_AT_language));
179+
auto source_language =
180+
static_cast<llvm::dwarf::SourceLanguage>(lang_attr.getAsUnsignedConstant().getValue());
181+
return std::make_pair(source_language, compiler);
182+
}
183+
157184
Status DwarfReader::DetectSourceLanguage() {
185+
is_multi_lang_ = false;
186+
std::optional<llvm::dwarf::SourceLanguage> prev_source_language;
187+
std::optional<std::string> prev_compiler;
158188
for (size_t i = 0; i < dwarf_context_->getNumCompileUnits(); ++i) {
159189
const auto& unit_die = dwarf_context_->getUnitAtIndex(i)->getUnitDIE();
160-
if (unit_die.getTag() != llvm::dwarf::DW_TAG_compile_unit) {
161-
// Skip over DW_TAG_partial_unit, and potentially other tags.
190+
auto lang_s = DetectSourceLanguageFromCUDIE(unit_die);
191+
if (!lang_s.ok()) {
162192
continue;
163193
}
164-
165-
PX_ASSIGN_OR(const DWARFFormValue& lang_attr,
166-
GetAttribute(unit_die, llvm::dwarf::DW_AT_language), continue);
167-
source_language_ =
168-
static_cast<llvm::dwarf::SourceLanguage>(lang_attr.getAsUnsignedConstant().getValue());
169-
170-
const DWARFFormValue& producer_attr =
171-
GetAttribute(unit_die, llvm::dwarf::DW_AT_producer).ValueOr({});
172-
173-
auto s = producer_attr.getAsCString();
174-
#if LLVM_VERSION_MAJOR >= 14
175-
if (!s.takeError()) {
176-
compiler_ = s.get();
194+
auto p = lang_s.ValueOrDie();
195+
auto source_language = p.first;
196+
auto& compiler = p.second;
197+
198+
if (!prev_source_language.has_value()) {
199+
prev_source_language = source_language;
200+
} else if (prev_source_language.has_value() &&
201+
prev_source_language.value() != source_language) {
202+
is_multi_lang_ = true;
177203
}
178-
#else
179-
compiler_ = s.getValueOr("");
180-
#endif
181204

205+
if (!prev_compiler.has_value()) {
206+
prev_compiler = compiler;
207+
} else if (prev_compiler.has_value() && prev_compiler.value() != compiler) {
208+
is_multi_lang_ = true;
209+
}
210+
}
211+
if (prev_source_language.has_value() && prev_compiler.has_value()) {
212+
source_language_ = prev_source_language.value();
182213
return Status::OK();
183214
}
184215
return error::Internal(
@@ -923,16 +954,20 @@ StatusOr<std::map<std::string, ArgInfo>> DwarfReader::GetFunctionArgInfo(
923954
// but DW_AT_location has been found to be blank in some cases, making it unreliable.
924955
// Instead, we use a FunctionArgTracker that tries to reverse engineer the calling convention.
925956

926-
ABI abi = LanguageToABI(source_language_, compiler_);
957+
PX_ASSIGN_OR_RETURN(const DWARFDie& function_die,
958+
GetMatchingDIE(function_symbol_name, llvm::dwarf::DW_TAG_subprogram));
959+
// Certain binaries can have DW_TAG_compile_units with different source languages. When compiling
960+
// programs with ASAN/TSAN enabled this is common.
961+
llvm::DWARFUnit* cu = function_die.getDwarfUnit();
962+
llvm::DWARFDie unit_die = cu->getUnitDIE();
963+
PX_ASSIGN_OR_RETURN(auto p, DetectSourceLanguageFromCUDIE(unit_die));
964+
ABI abi = LanguageToABI(p.first, p.second);
927965
if (abi == ABI::kUnknown) {
928966
return error::Unimplemented("Unable to determine ABI from language: $0",
929967
magic_enum::enum_name(source_language_));
930968
}
931969
std::unique_ptr<ABICallingConventionModel> arg_tracker = ABICallingConventionModel::Create(abi);
932970

933-
PX_ASSIGN_OR_RETURN(const DWARFDie& function_die,
934-
GetMatchingDIE(function_symbol_name, llvm::dwarf::DW_TAG_subprogram));
935-
936971
// If function has a return value, process that first.
937972
// This is important, because in some ABIs (e.g. SystemV ABI),
938973
// if the return value is not able to be passed back in the available registers,
@@ -968,7 +1003,7 @@ StatusOr<std::map<std::string, ArgInfo>> DwarfReader::GetFunctionArgInfo(
9681003
PX_ASSIGN_OR_RETURN(const DWARFDie type_die, GetTypeDie(die));
9691004
PX_ASSIGN_OR_RETURN(arg.type_info, GetTypeInfo(die, type_die));
9701005

971-
if (source_language_ == llvm::dwarf::DW_LANG_Go) {
1006+
if (p.first == llvm::dwarf::DW_LANG_Go) {
9721007
arg.retarg = IsGolangRetArg(die).ValueOr(false);
9731008
}
9741009

src/stirling/obj_tools/dwarf_reader.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ class DwarfReader {
178178
StatusOr<llvm::DWARFDie> GetMatchingDIE(std::string_view name,
179179
std::optional<llvm::dwarf::Tag> type = {});
180180

181+
/**
182+
* Detects the source language and compiler from a DW_TAG_compile_unit's attributes.
183+
*/
184+
StatusOr<std::pair<llvm::dwarf::SourceLanguage, std::string>> DetectSourceLanguageFromCUDIE(
185+
const llvm::DWARFDie& die);
186+
181187
/**
182188
* Return the size of a struct.
183189
*/
@@ -291,8 +297,18 @@ class DwarfReader {
291297

292298
bool IsValid() const { return dwarf_context_->getNumCompileUnits() != 0; }
293299

294-
const llvm::dwarf::SourceLanguage& source_language() const { return source_language_; }
295-
const std::string& compiler() const { return compiler_; }
300+
StatusOr<llvm::dwarf::SourceLanguage> source_language() const {
301+
if (!is_multi_lang_.has_value()) {
302+
return error::Internal(
303+
"source_language() called before the source language was detected. "
304+
"Call DetectSourceLanguage() first.");
305+
} else if (is_multi_lang_.value()) {
306+
return error::Internal(
307+
"source_language() called on a multi-language DWARF file. "
308+
"Use GetMatchingDIEs() to find the source language for a specific DIE.");
309+
}
310+
return source_language_;
311+
}
296312

297313
private:
298314
DwarfReader(std::unique_ptr<llvm::MemoryBuffer> buffer,
@@ -320,8 +336,7 @@ class DwarfReader {
320336
// Records the source language of the DWARF information.
321337
llvm::dwarf::SourceLanguage source_language_;
322338

323-
// Records the name of the compiler that produces this file.
324-
std::string compiler_;
339+
std::optional<bool> is_multi_lang_;
325340

326341
std::unique_ptr<llvm::MemoryBuffer> memory_buffer_;
327342
std::unique_ptr<llvm::DWARFContext> dwarf_context_;

src/stirling/obj_tools/dwarf_reader_test.cc

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,18 @@ class CppDwarfReaderTest : public ::testing::TestWithParam<DwarfReaderTestParam>
7272
void SetUp() override {
7373
DwarfReaderTestParam p = GetParam();
7474
ASSERT_OK_AND_ASSIGN(dwarf_reader, CreateDwarfReader(p.binary_path, p.index));
75+
indexed = p.index;
7576
}
7677
std::unique_ptr<DwarfReader> dwarf_reader;
78+
bool indexed;
7779
};
7880

7981
class GolangDwarfReaderTest : public ::testing::TestWithParam<DwarfReaderTestParam> {
8082
protected:
8183
void SetUp() override {
8284
DwarfReaderTestParam p = GetParam();
8385
ASSERT_OK_AND_ASSIGN(dwarf_reader, CreateDwarfReader(p.binary_path, p.index));
86+
indexed = p.index;
8487
}
8588

8689
StatusOr<SemVer> GetGoVersion() const {
@@ -97,6 +100,7 @@ class GolangDwarfReaderTest : public ::testing::TestWithParam<DwarfReaderTestPar
97100
}
98101

99102
std::unique_ptr<DwarfReader> dwarf_reader;
103+
bool indexed;
100104
};
101105

102106
class GolangDwarfReaderIndexTest : public ::testing::TestWithParam<bool> {
@@ -110,23 +114,54 @@ TEST_P(CppDwarfReaderTest, NonExistentPath) {
110114

111115
TEST_P(CppDwarfReaderTest, SourceLanguage) {
112116
{
113-
// We use C++17, but the dwarf shows 14.
114-
EXPECT_EQ(dwarf_reader->source_language(), llvm::dwarf::DW_LANG_C_plus_plus_14);
115-
EXPECT_THAT(dwarf_reader->compiler(), ::testing::HasSubstr("clang"));
117+
// Indexed DwarfReader's have source_language() populated, while non-indexed ones do not.
118+
auto source_lang_s = dwarf_reader->source_language();
119+
if (indexed) {
120+
// We use C++17, but the dwarf shows 14.
121+
EXPECT_EQ(source_lang_s.ValueOrDie(), llvm::dwarf::DW_LANG_C_plus_plus_14);
122+
} else {
123+
EXPECT_TRUE(!source_lang_s.ok());
124+
}
125+
126+
// Check that source language detect for individual DIEs works.
127+
ASSERT_OK_AND_ASSIGN(
128+
auto die, dwarf_reader->GetMatchingDIE("CanYouFindThis", llvm::dwarf::DW_TAG_subprogram));
129+
llvm::DWARFUnit* cu = die.getDwarfUnit();
130+
llvm::DWARFDie unit_die = cu->getUnitDIE();
131+
ASSERT_OK_AND_ASSIGN(auto p, dwarf_reader->DetectSourceLanguageFromCUDIE(unit_die));
132+
EXPECT_EQ(p.first, llvm::dwarf::DW_LANG_C_plus_plus_14);
133+
EXPECT_THAT(p.second, ::testing::HasSubstr("clang"));
116134
}
117135
}
118136

119137
TEST_P(GolangDwarfReaderTest, SourceLanguage) {
120138
{
121-
EXPECT_EQ(dwarf_reader->source_language(), llvm::dwarf::DW_LANG_Go);
122-
EXPECT_THAT(dwarf_reader->compiler(), ::testing::HasSubstr("go"));
139+
auto source_lang_s = dwarf_reader->source_language();
140+
// Indexed DwarfReader's have source_language() populated, while non-indexed ones do not.
141+
if (indexed) {
142+
if (source_lang_s.ok()) {
143+
EXPECT_EQ(source_lang_s.ValueOrDie(), llvm::dwarf::DW_LANG_Go);
144+
} else {
145+
ASSERT_THAT(std::string(source_lang_s.msg()),
146+
::testing::HasSubstr("multi-language DWARF file"));
147+
}
148+
} else {
149+
EXPECT_TRUE(!source_lang_s.ok());
150+
}
123151

152+
// Check that source language detect for individual DIEs works.
124153
ASSERT_OK_AND_ASSIGN(const bool uses_regabi, UsesRegABI());
125-
154+
ASSERT_OK_AND_ASSIGN(auto die, dwarf_reader->GetMatchingDIE("main.(*Vertex).Scale",
155+
llvm::dwarf::DW_TAG_subprogram));
156+
llvm::DWARFUnit* cu = die.getDwarfUnit();
157+
llvm::DWARFDie unit_die = cu->getUnitDIE();
158+
ASSERT_OK_AND_ASSIGN(auto p, dwarf_reader->DetectSourceLanguageFromCUDIE(unit_die));
126159
if (uses_regabi) {
127-
EXPECT_THAT(dwarf_reader->compiler(), ::testing::HasSubstr("regabi"));
160+
EXPECT_EQ(p.first, llvm::dwarf::DW_LANG_Go);
161+
EXPECT_THAT(p.second, ::testing::HasSubstr("regabi"));
128162
} else {
129-
EXPECT_THAT(dwarf_reader->compiler(), ::testing::Not(::testing::HasSubstr("regabi")));
163+
EXPECT_EQ(p.first, llvm::dwarf::DW_LANG_Go);
164+
EXPECT_THAT(p.second, ::testing::Not(::testing::HasSubstr("regabi")));
130165
}
131166
}
132167
}

src/stirling/source_connectors/dynamic_tracer/dynamic_tracing/autogen.cc

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,22 +61,33 @@ void DetectSourceLanguage(obj_tools::ElfReader* elf_reader, obj_tools::DwarfRead
6161

6262
// Primary detection mechanism is DWARF info, when available.
6363
if (dwarf_reader != nullptr) {
64-
detected_language = TransformSourceLanguage(dwarf_reader->source_language())
65-
.ConsumeValueOr(ir::shared::Language::LANG_UNKNOWN);
64+
// It's possible for DWARF to have DW_TAG_compile_unit's from multiple languages.
65+
// We currently only support binaries with a single language, so we
66+
// assert that this is the case.
67+
auto source_lang_s = dwarf_reader->source_language();
68+
if (source_lang_s.ok()) {
69+
auto source_lang = source_lang_s.ValueOrDie();
70+
detected_language =
71+
TransformSourceLanguage(source_lang).ConsumeValueOr(ir::shared::Language::LANG_UNKNOWN);
72+
LOG(INFO) << absl::Substitute("Using language $0 for object $1 and others",
73+
magic_enum::enum_name(source_lang),
74+
input_program->deployment_spec().path_list().paths(0));
75+
76+
} else {
77+
detected_language = ir::shared::Language::LANG_UNKNOWN;
78+
}
6679
} else {
6780
// Back-up detection policy looks for certain language-specific symbols
6881
if (IsGoExecutable(elf_reader)) {
6982
detected_language = ir::shared::Language::GOLANG;
83+
LOG(INFO) << absl::Substitute("Using language GOLANG for object $1 and others",
84+
input_program->deployment_spec().path_list().paths(0));
7085
}
7186

7287
// TODO(oazizi): Make this stronger by adding more elf-based tests.
7388
}
7489

7590
if (detected_language != ir::shared::Language::LANG_UNKNOWN) {
76-
LOG(INFO) << absl::Substitute("Using language $0 for object $1 and others",
77-
magic_enum::enum_name(dwarf_reader->source_language()),
78-
input_program->deployment_spec().path_list().paths(0));
79-
8091
// Since we only support tracing of a single object, all tracepoints have the same language.
8192
for (auto& tracepoint : *input_program->mutable_tracepoints()) {
8293
tracepoint.mutable_program()->set_language(detected_language);

src/stirling/source_connectors/socket_tracer/bcc_bpf/go_http2_trace.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,7 @@ static __inline int32_t get_fd_from_http_http2Framer(const void* framer_ptr,
161161
}
162162

163163
struct go_interface inner_intf;
164-
BPF_PROBE_READ_VAR(inner_intf,
165-
io_writer_interface.ptr + inner_intf_offset);
164+
BPF_PROBE_READ_VAR(inner_intf, io_writer_interface.ptr + inner_intf_offset);
166165

167166
if (conn_intf) {
168167
return get_fd_from_conn_intf(inner_intf);

0 commit comments

Comments
 (0)