Skip to content

Commit 1ad28c4

Browse files
authored
Remove DwarfReader::DetectSourceLanguage API to address issues with multi language binaries (#2228)
Summary: Remove `DwarfReader::DetectSourceLanguage` API to address issues with multi language binaries Our previous `DwarfReader::DetectSourceLanguage` API assumes that a binary contains a single type of `DW_AT_language` attribute -- meaning a Go binary would include only DIEs with `DW_AT_language=DW_LANG_Go`. With our upgrade to Go 1.24, this assumption is no longer true. For example, Go binaries built under ASAN contain a variety of `DW_AT_language` attribute values depending on the DIE compile unit (see Test plan output). This PR removes this API and updates all callers to determine their use case's language from the relevant compile unit DIE. Relevant Issues: N/A Type of change: /kind bugfix Test Plan: Verified that the tests introduced in commit 1 fail w/ ASAN enabled. New APIs fix the build <details><summary>verification steps</summary> ``` # Tests fail under ASAN since C/C++ ABI is incorrectly assumed (17a0121...)$ bazel test --config asan src/stirling/source_connectors/socket_tracer:uprobe_symaddrs_test --test_output=all --nocache_test_results [==========] Running 4 tests from 2 test suites. [----------] Global test environment set-up. [----------] 3 tests from UprobeSymaddrsTest [ RUN ] UprobeSymaddrsTest.GoCommonSymAddrs [ OK ] UprobeSymaddrsTest.GoCommonSymAddrs (1768 ms) [ RUN ] UprobeSymaddrsTest.GoHTTP2SymAddrs src/stirling/source_connectors/socket_tracer/uprobe_symaddrs_test.cc:83: Failure Expected equality of these values: symaddrs.writeHeader_hf_ptr_loc Which is: type=kLocationTypeStack offset=8 (location_t{.type = kLocationTypeRegisters, .offset = 24}) Which is: type=kLocationTypeRegisters offset=24 [ FAILED ] UprobeSymaddrsTest.GoHTTP2SymAddrs (1728 ms) [ RUN ] UprobeSymaddrsTest.GoTLSSymAddrs src/stirling/source_connectors/socket_tracer/uprobe_symaddrs_test.cc:94: Failure Expected equality of these values: symaddrs.Write_b_loc Which is: type=kLocationTypeStack offset=8 (location_t{.type = kLocationTypeRegisters, .offset = 8}) Which is: type=kLocationTypeRegisters offset=8 src/stirling/source_connectors/socket_tracer/uprobe_symaddrs_test.cc:96: Failure Expected equality of these values: symaddrs.Read_b_loc Which is: type=kLocationTypeStack offset=8 (location_t{.type = kLocationTypeRegisters, .offset = 8}) Which is: type=kLocationTypeRegisters offset=8 [ FAILED ] UprobeSymaddrsTest.GoTLSSymAddrs (1613 ms) [----------] 3 tests from UprobeSymaddrsTest (5110 ms total) [----------] 1 test from UprobeSymaddrsNodeTest [ RUN ] UprobeSymaddrsNodeTest.TLSWrapSymAddrsFromDwarfInfo [ OK ] UprobeSymaddrsNodeTest.TLSWrapSymAddrsFromDwarfInfo (1 ms) [----------] 1 test from UprobeSymaddrsNodeTest (1 ms total) [----------] Global test environment tear-down [==========] 4 tests from 2 test suites ran. (5111 ms total) [ PASSED ] 2 tests. [ FAILED ] 2 tests, listed below: [ FAILED ] UprobeSymaddrsTest.GoHTTP2SymAddrs [ FAILED ] UprobeSymaddrsTest.GoTLSSymAddrs 2 FAILED TESTS I20250710 06:18:14.281155 12 env.cc:51] Shutting down ================================================================================ Target //src/stirling/source_connectors/socket_tracer:uprobe_symaddrs_test up-to-date: bazel-bin/src/stirling/source_connectors/socket_tracer/uprobe_symaddrs_test INFO: Elapsed time: 5.657s, Critical Path: 5.38s INFO: 2 processes: 1 internal, 1 linux-sandbox. INFO: Build completed, 1 test FAILED, 2 total actions //src/stirling/source_connectors/socket_tracer:uprobe_symaddrs_test FAILED in 5.4s /home/ddelnano/.cache/bazel/_bazel_ddelnano/fa8604ca46879b9b1ffd44d337c531f3/execroot/px/bazel-out/k8-fastbuild/testlogs/src/stirling/source_connectors/socket_tracer/uprobe_symaddrs_test/test.log Executed 1 out of 1 test: 1 fails locally. # Verify ASAN build has DIEs with different DW_AT_language attributes (17a0121...) $ bazel build --config asan src/stirling/testing/demo_apps/go_grpc_tls_pl/server:golang_1_24_grpc_tls_server_binary (17a0121...) $ llvm-dwarfdump bazel-bin/src/stirling/testing/demo_apps/go_grpc_tls_pl/server/golang_1_24_grpc_tls_server_binary | grep DW_AT_lang | uniq -c 1 DW_AT_language (DW_LANG_C_plus_plus_14) 1 DW_AT_language (DW_LANG_Mips_Assembler) 22 DW_AT_language (DW_LANG_C_plus_plus_14) 1 DW_AT_language (DW_LANG_Mips_Assembler) 48 DW_AT_language (DW_LANG_C_plus_plus_14) 280 DW_AT_language (DW_LANG_Go) # Verify non ASAN builds have only one DW_AT_language attribute (17a0121...) $ bazel build src/stirling/testing/demo_apps/go_grpc_tls_pl/server:golang_1_24_grpc_tls_server_binary (17a0121...) $ llvm-dwarfdump bazel-bin/src/stirling/testing/demo_apps/go_grpc_tls_pl/server/golang_1_24_grpc_tls_server_binary | grep DW_AT_lang | uniq -c 281 DW_AT_language (DW_LANG_Go) ``` </details> --------- Signed-off-by: Dom Del Nano <[email protected]>
1 parent b3c810f commit 1ad28c4

File tree

10 files changed

+114
-98
lines changed

10 files changed

+114
-98
lines changed

src/stirling/obj_tools/dwarf_reader.cc

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,6 @@ 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

@@ -154,36 +152,29 @@ bool IsNamespace(llvm::dwarf::Tag tag) { return tag == llvm::dwarf::DW_TAG_names
154152

155153
} // namespace
156154

157-
Status DwarfReader::DetectSourceLanguage() {
158-
for (size_t i = 0; i < dwarf_context_->getNumCompileUnits(); ++i) {
159-
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.
162-
continue;
163-
}
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();
155+
StatusOr<std::pair<llvm::dwarf::SourceLanguage, std::string>>
156+
DwarfReader::DetectSourceLanguageFromCUDIE(const llvm::DWARFDie& unit_die) {
157+
if (unit_die.getTag() != llvm::dwarf::DW_TAG_compile_unit) {
158+
// Skip over DW_TAG_partial_unit, and potentially other tags.
159+
return error::NotFound("Expected DW_TAG_compile_unit, but got DW_TAG=$0 for unit DIE: $1",
160+
magic_enum::enum_name(unit_die.getTag()), Dump(unit_die));
161+
}
162+
const DWARFFormValue& producer_attr =
163+
GetAttribute(unit_die, llvm::dwarf::DW_AT_producer).ValueOr({});
164+
auto s = producer_attr.getAsCString();
165+
std::string compiler;
174166
#if LLVM_VERSION_MAJOR >= 14
175-
if (!s.takeError()) {
176-
compiler_ = s.get();
177-
}
167+
if (!s.takeError()) {
168+
compiler = s.get();
169+
}
178170
#else
179-
compiler_ = s.getValueOr("");
171+
compiler = s.getValueOr("");
180172
#endif
181-
182-
return Status::OK();
183-
}
184-
return error::Internal(
185-
"Could not determine the source language of the DWARF info. DW_AT_language not found on "
186-
"any compilation unit.");
173+
PX_ASSIGN_OR_RETURN(const DWARFFormValue& lang_attr,
174+
GetAttribute(unit_die, llvm::dwarf::DW_AT_language));
175+
auto source_language =
176+
static_cast<llvm::dwarf::SourceLanguage>(lang_attr.getAsUnsignedConstant().getValue());
177+
return std::make_pair(source_language, compiler);
187178
}
188179

189180
void DwarfReader::IndexDIEs(
@@ -923,16 +914,21 @@ StatusOr<std::map<std::string, ArgInfo>> DwarfReader::GetFunctionArgInfo(
923914
// but DW_AT_location has been found to be blank in some cases, making it unreliable.
924915
// Instead, we use a FunctionArgTracker that tries to reverse engineer the calling convention.
925916

926-
ABI abi = LanguageToABI(source_language_, compiler_);
917+
PX_ASSIGN_OR_RETURN(const DWARFDie& function_die,
918+
GetMatchingDIE(function_symbol_name, llvm::dwarf::DW_TAG_subprogram));
919+
// Certain binaries can have DW_TAG_compile_units with different source languages. When compiling
920+
// programs with ASAN/TSAN enabled this is common.
921+
llvm::DWARFUnit* cu = function_die.getDwarfUnit();
922+
llvm::DWARFDie unit_die = cu->getUnitDIE();
923+
PX_ASSIGN_OR_RETURN(auto source_lang_info, DetectSourceLanguageFromCUDIE(unit_die));
924+
auto [source_lang, compiler] = source_lang_info;
925+
ABI abi = LanguageToABI(source_lang, compiler);
927926
if (abi == ABI::kUnknown) {
928927
return error::Unimplemented("Unable to determine ABI from language: $0",
929-
magic_enum::enum_name(source_language_));
928+
magic_enum::enum_name(source_lang));
930929
}
931930
std::unique_ptr<ABICallingConventionModel> arg_tracker = ABICallingConventionModel::Create(abi);
932931

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

971-
if (source_language_ == llvm::dwarf::DW_LANG_Go) {
967+
if (source_lang == llvm::dwarf::DW_LANG_Go) {
972968
arg.retarg = IsGolangRetArg(die).ValueOr(false);
973969
}
974970

src/stirling/obj_tools/dwarf_reader.h

Lines changed: 6 additions & 12 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,16 +297,10 @@ 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_; }
296-
297300
private:
298301
DwarfReader(std::unique_ptr<llvm::MemoryBuffer> buffer,
299302
std::unique_ptr<llvm::DWARFContext> dwarf_context);
300303

301-
// Detects the source language of the dwarf content being read.
302-
Status DetectSourceLanguage();
303-
304304
// Builds an index for certain commonly used DIE types (e.g. structs and functions).
305305
// When making multiple DwarfReader calls, this speeds up the process at the cost of some memory.
306306
//
@@ -317,12 +317,6 @@ class DwarfReader {
317317
void InsertToDIEMap(std::string name, llvm::dwarf::Tag tag, llvm::DWARFDie die);
318318
std::optional<llvm::DWARFDie> FindInDIEMap(const std::string& name, llvm::dwarf::Tag tag) const;
319319

320-
// Records the source language of the DWARF information.
321-
llvm::dwarf::SourceLanguage source_language_;
322-
323-
// Records the name of the compiler that produces this file.
324-
std::string compiler_;
325-
326320
std::unique_ptr<llvm::MemoryBuffer> memory_buffer_;
327321
std::unique_ptr<llvm::DWARFContext> dwarf_context_;
328322

src/stirling/obj_tools/dwarf_reader_test.cc

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,23 +125,32 @@ TEST_P(CppDwarfReaderTest, NonExistentPath) {
125125

126126
TEST_P(CppDwarfReaderTest, SourceLanguage) {
127127
{
128+
// Check that source language detect for individual DIEs works.
129+
ASSERT_OK_AND_ASSIGN(
130+
auto die, dwarf_reader->GetMatchingDIE("CanYouFindThis", llvm::dwarf::DW_TAG_subprogram));
131+
llvm::DWARFUnit* cu = die.getDwarfUnit();
132+
llvm::DWARFDie unit_die = cu->getUnitDIE();
133+
ASSERT_OK_AND_ASSIGN(auto p, dwarf_reader->DetectSourceLanguageFromCUDIE(unit_die));
128134
// We use C++17, but the dwarf shows 14.
129-
EXPECT_EQ(dwarf_reader->source_language(), llvm::dwarf::DW_LANG_C_plus_plus_14);
130-
EXPECT_THAT(dwarf_reader->compiler(), ::testing::HasSubstr("clang"));
135+
EXPECT_EQ(p.first, llvm::dwarf::DW_LANG_C_plus_plus_14);
136+
EXPECT_THAT(p.second, ::testing::HasSubstr("clang"));
131137
}
132138
}
133139

134140
TEST_P(GolangDwarfReaderTest, SourceLanguage) {
135141
{
136-
EXPECT_EQ(dwarf_reader->source_language(), llvm::dwarf::DW_LANG_Go);
137-
EXPECT_THAT(dwarf_reader->compiler(), ::testing::HasSubstr("go"));
138-
142+
// Check that source language detect for individual DIEs works.
139143
ASSERT_OK_AND_ASSIGN(const bool uses_regabi, UsesRegABI());
140-
144+
ASSERT_OK_AND_ASSIGN(auto die, dwarf_reader->GetMatchingDIE("main.(*Vertex).Scale",
145+
llvm::dwarf::DW_TAG_subprogram));
146+
llvm::DWARFUnit* cu = die.getDwarfUnit();
147+
llvm::DWARFDie unit_die = cu->getUnitDIE();
148+
ASSERT_OK_AND_ASSIGN(auto p, dwarf_reader->DetectSourceLanguageFromCUDIE(unit_die));
149+
EXPECT_EQ(p.first, llvm::dwarf::DW_LANG_Go);
141150
if (uses_regabi) {
142-
EXPECT_THAT(dwarf_reader->compiler(), ::testing::HasSubstr("regabi"));
151+
EXPECT_THAT(p.second, ::testing::HasSubstr("regabi"));
143152
} else {
144-
EXPECT_THAT(dwarf_reader->compiler(), ::testing::Not(::testing::HasSubstr("regabi")));
153+
EXPECT_THAT(p.second, ::testing::Not(::testing::HasSubstr("regabi")));
145154
}
146155
}
147156
}

src/stirling/obj_tools/elf_reader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class ElfReader {
6262
const std::string& binary_path, const std::filesystem::path& debug_file_dir = kDebugFileDir);
6363

6464
std::filesystem::path& debug_symbols_path() { return debug_symbols_path_; }
65+
const std::string& binary_path() const { return binary_path_; }
6566

6667
struct SymbolInfo {
6768
std::string name;

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

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ StatusOr<ir::shared::Language> TransformSourceLanguage(
4242
return ir::shared::Language::GOLANG;
4343
case llvm::dwarf::DW_LANG_C:
4444
case llvm::dwarf::DW_LANG_C99:
45+
case llvm::dwarf::DW_LANG_C11:
4546
case llvm::dwarf::DW_LANG_C_plus_plus:
4647
case llvm::dwarf::DW_LANG_C_plus_plus_03:
4748
case llvm::dwarf::DW_LANG_C_plus_plus_11:
@@ -53,42 +54,49 @@ StatusOr<ir::shared::Language> TransformSourceLanguage(
5354
}
5455
}
5556

57+
StatusOr<ir::shared::Language> TryDetectSourceLanguageFromDwarf(
58+
obj_tools::DwarfReader* dwarf_reader, const std::string& symbol_name) {
59+
PX_ASSIGN_OR_RETURN(const auto& function_die,
60+
dwarf_reader->GetMatchingDIE(symbol_name, llvm::dwarf::DW_TAG_subprogram));
61+
llvm::DWARFUnit* cu = function_die.getDwarfUnit();
62+
llvm::DWARFDie unit_die = cu->getUnitDIE();
63+
64+
PX_ASSIGN_OR_RETURN(auto lang_pair, dwarf_reader->DetectSourceLanguageFromCUDIE(unit_die));
65+
llvm::dwarf::SourceLanguage source_lang = lang_pair.first;
66+
PX_ASSIGN_OR_RETURN(auto detected_language, TransformSourceLanguage(source_lang));
67+
68+
return detected_language;
69+
}
70+
5671
} // namespace
5772

5873
void DetectSourceLanguage(obj_tools::ElfReader* elf_reader, obj_tools::DwarfReader* dwarf_reader,
59-
ir::logical::TracepointDeployment* input_program) {
74+
ir::logical::TracepointSpec* program, const std::string& symbol_name) {
6075
ir::shared::Language detected_language = ir::shared::Language::LANG_UNKNOWN;
61-
6276
// Primary detection mechanism is DWARF info, when available.
6377
if (dwarf_reader != nullptr) {
64-
detected_language = TransformSourceLanguage(dwarf_reader->source_language())
65-
.ConsumeValueOr(ir::shared::Language::LANG_UNKNOWN);
78+
auto result = TryDetectSourceLanguageFromDwarf(dwarf_reader, symbol_name);
79+
if (result.ok()) {
80+
detected_language = result.ConsumeValueOrDie();
81+
}
6682
} else {
6783
// Back-up detection policy looks for certain language-specific symbols
6884
if (IsGoExecutable(elf_reader)) {
6985
detected_language = ir::shared::Language::GOLANG;
7086
}
71-
72-
// TODO(oazizi): Make this stronger by adding more elf-based tests.
7387
}
7488

7589
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-
80-
// Since we only support tracing of a single object, all tracepoints have the same language.
81-
for (auto& tracepoint : *input_program->mutable_tracepoints()) {
82-
tracepoint.mutable_program()->set_language(detected_language);
83-
}
90+
program->set_language(detected_language);
91+
LOG(INFO) << absl::Substitute("Using language $0 for object $1 and symbol $2",
92+
magic_enum::enum_name(detected_language),
93+
elf_reader->binary_path(), symbol_name);
8494
} else {
85-
// For now, just print a warning, and let the probe proceed.
86-
// This is so we can use things like function argument tracing even when other features may not
87-
// work.
95+
// Fall back to warning and assume C/C++ ABI
8896
LOG(WARNING) << absl::Substitute(
8997
"Language for object $0 and others is unknown or unsupported, so assuming C/C++ ABI. "
9098
"Some dynamic tracing features may not work, or may produce unexpected results.",
91-
input_program->deployment_spec().path_list().paths(0));
99+
elf_reader->binary_path());
92100
}
93101
}
94102
namespace {
@@ -110,8 +118,9 @@ bool IsWholeWordSuffix(std::string_view name, std::string_view suffix) {
110118

111119
} // namespace
112120

113-
Status ResolveProbeSymbol(obj_tools::ElfReader* elf_reader,
114-
ir::logical::TracepointDeployment* input_program) {
121+
Status ResolveProbeSymbolAndLanguage(obj_tools::ElfReader* elf_reader,
122+
obj_tools::DwarfReader* dwarf_reader,
123+
ir::logical::TracepointDeployment* input_program) {
115124
// Expand symbol
116125
for (auto& t : *input_program->mutable_tracepoints()) {
117126
for (auto& probe : *t.mutable_program()->mutable_probes()) {
@@ -156,7 +165,9 @@ Status ResolveProbeSymbol(obj_tools::ElfReader* elf_reader,
156165
return error::Internal("Could not find valid symbol match");
157166
}
158167

159-
*probe.mutable_tracepoint()->mutable_symbol() = *symbol_name;
168+
auto tracepoint = probe.mutable_tracepoint();
169+
*tracepoint->mutable_symbol() = *symbol_name;
170+
DetectSourceLanguage(elf_reader, dwarf_reader, t.mutable_program(), *symbol_name);
160171
}
161172
}
162173

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
#pragma once
2020

21+
#include <string>
22+
2123
#include "src/common/base/base.h"
2224
#include "src/stirling/obj_tools/dwarf_reader.h"
2325
#include "src/stirling/obj_tools/elf_reader.h"
@@ -31,18 +33,22 @@ namespace dynamic_tracing {
3133
/**
3234
* Uses ELF or DWARF information to detect the source language.
3335
* Populates the tracepoint program's language field in input_program.
36+
* If the language cannot be determined, it assumes a C/C++ language ABI.
3437
*/
3538
void DetectSourceLanguage(obj_tools::ElfReader* elf_reader, obj_tools::DwarfReader* dwarf_reader,
36-
ir::logical::TracepointDeployment* input_program);
39+
ir::logical::TracepointSpec* program, const std::string& symbol_name);
3740

3841
/**
3942
* Uses ELF information to check if the provided symbol exists.
4043
* If it does not exist, it checks whether it is a short-hand (suffix) of a full symbol.
4144
* If it is a short-hand reference to a symbol, the symbol is replaced with the full-form.
42-
* Potentially modifies each tracepoint's symbol field in input_program.
45+
* Also detects the source language for each resolved symbol using DWARF or ELF information.
46+
* Potentially modifies each tracepoint's symbol field and program's language field in
47+
* input_program.
4348
*/
44-
Status ResolveProbeSymbol(obj_tools::ElfReader* elf_reader,
45-
ir::logical::TracepointDeployment* input_program);
49+
Status ResolveProbeSymbolAndLanguage(obj_tools::ElfReader* elf_reader,
50+
obj_tools::DwarfReader* dwarf_reader,
51+
ir::logical::TracepointDeployment* input_program);
4652

4753
/**
4854
* If any tracepoint in input_program contains no fields to trace, this function uses DWARF info

0 commit comments

Comments
 (0)