Skip to content
Merged
11 changes: 10 additions & 1 deletion src/stirling/binaries/go_binary_parse_profiling.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
#include "src/stirling/source_connectors/socket_tracer/uprobe_symaddrs.h"

using px::StatusOr;
using px::stirling::GoOffsetLocator;
using px::stirling::PopulateGoTLSDebugSymbols;
using px::stirling::obj_tools::DwarfReader;
using px::stirling::obj_tools::ElfReader;
using px::stirling::obj_tools::ReadGoBuildInfo;

//-----------------------------------------------------------------------------
// This utility is designed to isolate parsing the debug symbols of a Go binary. This
Expand Down Expand Up @@ -62,8 +64,15 @@ int main(int argc, char** argv) {
}
std::unique_ptr<DwarfReader> dwarf_reader = dwarf_reader_status.ConsumeValueOrDie();

auto build_info_s = ReadGoBuildInfo(elf_reader.get());
const auto& [go_version, build_info] = build_info_s.ConsumeValueOrDie();
px::stirling::StructOffsetMap struct_offsets;
px::stirling::FunctionArgMap function_args;
std::unique_ptr<GoOffsetLocator> go_offset_locator = std::make_unique<GoOffsetLocator>(
dwarf_reader.get(), struct_offsets, function_args, build_info, go_version);

struct go_tls_symaddrs_t symaddrs;
auto status = PopulateGoTLSDebugSymbols(elf_reader.get(), dwarf_reader.get(), &symaddrs);
auto status = PopulateGoTLSDebugSymbols(go_offset_locator.get(), &symaddrs);

if (!status.ok()) {
LOG(ERROR) << absl::Substitute("debug symbol parsing failed with: $0", status.msg());
Expand Down
48 changes: 35 additions & 13 deletions src/stirling/source_connectors/socket_tracer/uprobe_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,10 @@ Status UProbeManager::UpdateOpenSSLSymAddrs(obj_tools::RawFptrManager* fptr_mana
return Status::OK();
}

Status UProbeManager::UpdateGoCommonSymAddrs(ElfReader* elf_reader, DwarfReader* dwarf_reader,
Status UProbeManager::UpdateGoCommonSymAddrs(ElfReader* elf_reader, GoOffsetLocator* offset_locator,
const std::vector<int32_t>& pids) {
PX_ASSIGN_OR_RETURN(struct go_common_symaddrs_t symaddrs,
GoCommonSymAddrs(elf_reader, dwarf_reader));
GoCommonSymAddrs(elf_reader, offset_locator));

for (auto& pid : pids) {
PX_RETURN_IF_ERROR(go_common_symaddrs_map_->SetValue(pid, symaddrs));
Expand All @@ -186,10 +186,10 @@ Status UProbeManager::UpdateGoCommonSymAddrs(ElfReader* elf_reader, DwarfReader*
return Status::OK();
}

Status UProbeManager::UpdateGoHTTP2SymAddrs(ElfReader* elf_reader, DwarfReader* dwarf_reader,
Status UProbeManager::UpdateGoHTTP2SymAddrs(ElfReader* elf_reader, GoOffsetLocator* offset_locator,
const std::vector<int32_t>& pids) {
PX_ASSIGN_OR_RETURN(struct go_http2_symaddrs_t symaddrs,
GoHTTP2SymAddrs(elf_reader, dwarf_reader));
GoHTTP2SymAddrs(elf_reader, offset_locator));

for (auto& pid : pids) {
PX_RETURN_IF_ERROR(go_http2_symaddrs_map_->SetValue(pid, symaddrs));
Expand All @@ -198,9 +198,9 @@ Status UProbeManager::UpdateGoHTTP2SymAddrs(ElfReader* elf_reader, DwarfReader*
return Status::OK();
}

Status UProbeManager::UpdateGoTLSSymAddrs(ElfReader* elf_reader, DwarfReader* dwarf_reader,
Status UProbeManager::UpdateGoTLSSymAddrs(GoOffsetLocator* offset_locator,
const std::vector<int32_t>& pids) {
PX_ASSIGN_OR_RETURN(struct go_tls_symaddrs_t symaddrs, GoTLSSymAddrs(elf_reader, dwarf_reader));
PX_ASSIGN_OR_RETURN(struct go_tls_symaddrs_t symaddrs, GoTLSSymAddrs(offset_locator));

for (auto& pid : pids) {
PX_RETURN_IF_ERROR(go_tls_symaddrs_map_->SetValue(pid, symaddrs));
Expand Down Expand Up @@ -524,10 +524,10 @@ StatusOr<int> UProbeManager::AttachNodeJsOpenSSLUprobes(const uint32_t pid,

StatusOr<int> UProbeManager::AttachGoTLSUProbes(const std::string& binary,
obj_tools::ElfReader* elf_reader,
obj_tools::DwarfReader* dwarf_reader,
GoOffsetLocator* offset_locator,
const std::vector<int32_t>& pids) {
// Step 1: Update BPF symbols_map on all new PIDs.
Status s = UpdateGoTLSSymAddrs(elf_reader, dwarf_reader, pids);
Status s = UpdateGoTLSSymAddrs(offset_locator, pids);
if (!s.ok()) {
// Doesn't appear to be a binary with the mandatory symbols.
// Might not even be a golang binary.
Expand All @@ -546,10 +546,10 @@ StatusOr<int> UProbeManager::AttachGoTLSUProbes(const std::string& binary,

StatusOr<int> UProbeManager::AttachGoHTTP2UProbes(const std::string& binary,
obj_tools::ElfReader* elf_reader,
obj_tools::DwarfReader* dwarf_reader,
GoOffsetLocator* offset_locator,
const std::vector<int32_t>& pids) {
// Step 1: Update BPF symaddrs for this binary.
Status s = UpdateGoHTTP2SymAddrs(elf_reader, dwarf_reader, pids);
Status s = UpdateGoHTTP2SymAddrs(elf_reader, offset_locator, pids);
if (!s.ok()) {
return 0;
}
Expand Down Expand Up @@ -886,8 +886,30 @@ int UProbeManager::DeployGoUProbes(const absl::flat_hash_set<md::UPID>& pids) {
binary, dwarf_reader_status.msg());
continue;
}

auto build_info_s = ReadGoBuildInfo(elf_reader.get());
obj_tools::BuildInfo build_info;
std::string go_version;
if (build_info_s.ok()) {
auto& build_info_pair = build_info_s.ValueOrDie();
go_version = build_info_pair.first;
build_info = std::move(build_info_pair.second);
} else {
VLOG(1) << absl::Substitute("Failed to read build info from binary $0. Message = $1", binary,
build_info_s.status().msg());

continue;
}

std::unique_ptr<DwarfReader> dwarf_reader = dwarf_reader_status.ConsumeValueOrDie();
Status s = UpdateGoCommonSymAddrs(elf_reader.get(), dwarf_reader.get(), pid_vec);

// TODO(ddelnano): The struct and function offsets will be populated by the
// next set of changes.
StructOffsetMap struct_offsets;
FunctionArgMap function_offsets;
std::unique_ptr<GoOffsetLocator> offset_locator = std::make_unique<GoOffsetLocator>(
dwarf_reader.get(), struct_offsets, function_offsets, build_info, go_version);
Status s = UpdateGoCommonSymAddrs(elf_reader.get(), offset_locator.get(), pid_vec);
if (!s.ok()) {
VLOG(1) << absl::Substitute(
"Golang binary $0 does not have the mandatory symbols (e.g. TCPConn).", binary);
Expand All @@ -898,7 +920,7 @@ int UProbeManager::DeployGoUProbes(const absl::flat_hash_set<md::UPID>& pids) {
if (!cfg_disable_go_tls_tracing_) {
VLOG(1) << absl::Substitute("Attempting to attach Go TLS uprobes to binary $0", binary);
StatusOr<int> attach_status =
AttachGoTLSUProbes(binary, elf_reader.get(), dwarf_reader.get(), pid_vec);
AttachGoTLSUProbes(binary, elf_reader.get(), offset_locator.get(), pid_vec);
if (!attach_status.ok()) {
monitor_.AppendSourceStatusRecord("socket_tracer", attach_status.status(),
"AttachGoTLSUProbes");
Expand All @@ -912,7 +934,7 @@ int UProbeManager::DeployGoUProbes(const absl::flat_hash_set<md::UPID>& pids) {
// Go HTTP2 Probes.
if (!cfg_disable_go_tls_tracing_ && cfg_enable_http2_tracing_) {
StatusOr<int> attach_status =
AttachGoHTTP2UProbes(binary, elf_reader.get(), dwarf_reader.get(), pid_vec);
AttachGoHTTP2UProbes(binary, elf_reader.get(), offset_locator.get(), pid_vec);
if (!attach_status.ok()) {
monitor_.AppendSourceStatusRecord("socket_tracer", attach_status.status(),
"AttachGoHTTP2UProbes");
Expand Down
17 changes: 7 additions & 10 deletions src/stirling/source_connectors/socket_tracer/uprobe_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -493,15 +493,15 @@ class UProbeManager {
*
* @param binary The path to the binary on which to deploy Go HTTP2 probes.
* @param elf_reader ELF reader for the binary.
* @param dwarf_reader DWARF reader for the binary.
* @param offset_locator DWARF reader for the binary.
* @param pids The list of PIDs that are new instances of the binary. Used to populate symbol
* addresses.
* @return The number of uprobes deployed, or error. It is not considered an error if the binary
* is not a Go binary or doesn't use a Go HTTP2 library; instead the return value will be
* zero.
*/
StatusOr<int> AttachGoHTTP2UProbes(const std::string& binary, obj_tools::ElfReader* elf_reader,
obj_tools::DwarfReader* dwarf_reader,
GoOffsetLocator* offset_locator,
const std::vector<int32_t>& pids);

/**
Expand All @@ -510,14 +510,14 @@ class UProbeManager {
*
* @param binary The path to the binary on which to deploy Go HTTP2 probes.
* @param elf_reader ELF reader for the binary.
* @param dwarf_reader DWARF reader for the binary.
* @param offset_locator DWARF reader for the binary.
* @param pids The list of PIDs that are new instances of the binary. Used to populate symbol
* addresses.
* @return The number of uprobes deployed, or error. It is not an error if the binary
* is not a Go binary or doesn't use Go TLS; instead the return value will be zero.
*/
StatusOr<int> AttachGoTLSUProbes(const std::string& binary, obj_tools::ElfReader* elf_reader,
obj_tools::DwarfReader* dwarf_reader,
GoOffsetLocator* offset_locator,
const std::vector<int32_t>& new_pids);

/**
Expand Down Expand Up @@ -579,14 +579,11 @@ class UProbeManager {

Status UpdateOpenSSLSymAddrs(px::stirling::obj_tools::RawFptrManager* fptrManager,
std::filesystem::path container_lib, uint32_t pid);
Status UpdateGoCommonSymAddrs(obj_tools::ElfReader* elf_reader,
obj_tools::DwarfReader* dwarf_reader,
Status UpdateGoCommonSymAddrs(obj_tools::ElfReader* elf_reader, GoOffsetLocator* offset_locator,
const std::vector<int32_t>& pids);
Status UpdateGoHTTP2SymAddrs(obj_tools::ElfReader* elf_reader,
obj_tools::DwarfReader* dwarf_reader,
Status UpdateGoHTTP2SymAddrs(obj_tools::ElfReader* elf_reader, GoOffsetLocator* offset_locator,
const std::vector<int32_t>& pids);
Status UpdateGoTLSSymAddrs(obj_tools::ElfReader* elf_reader, obj_tools::DwarfReader* dwarf_reader,
const std::vector<int32_t>& pids);
Status UpdateGoTLSSymAddrs(GoOffsetLocator* offset_locator, const std::vector<int32_t>& pids);
Status UpdateNodeTLSWrapSymAddrs(int32_t pid, const std::filesystem::path& node_exe,
const SemVer& ver);

Expand Down
Loading