Skip to content

Commit b19cad7

Browse files
committed
Simplify mod info parsing logic. Update tests to ensure endian specific case works
Signed-off-by: Dom Del Nano <ddelnano@gmail.com>
1 parent b776f69 commit b19cad7

2 files changed

Lines changed: 72 additions & 60 deletions

File tree

src/stirling/obj_tools/go_syms.cc

Lines changed: 66 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -171,82 +171,88 @@ StatusOr<std::pair<std::string, BuildInfo>> ReadGoBuildInfo(ElfReader* elf_reade
171171
PX_ASSIGN_OR_RETURN(uint8_t endianness, binary_decoder.ExtractBEInt<uint8_t>());
172172

173173
BuildInfo build_info;
174+
std::string go_version;
175+
std::string mod_info;
174176
// If the endianness has its second bit set, then the go version immediately follows the 32 bit
175177
// header specified by the varint encoded string data
176178
if ((endianness & 0x2) != 0) {
177179
// Skip the remaining 16 bytes of buildinfo header
178180
PX_CHECK_OK(binary_decoder.ExtractBufIgnore(16));
179181

180182
PX_ASSIGN_OR_RETURN(uint64_t size, binary_decoder.ExtractUVarInt());
181-
PX_ASSIGN_OR_RETURN(std::string_view go_version, binary_decoder.ExtractString(size));
183+
PX_ASSIGN_OR_RETURN(go_version, binary_decoder.ExtractString(size));
182184

183185
PX_ASSIGN_OR_RETURN(uint64_t mod_size, binary_decoder.ExtractUVarInt());
184-
PX_ASSIGN_OR_RETURN(std::string_view mod, binary_decoder.ExtractString(mod_size));
185-
if (mod_size >= 33 && mod.at(mod_size - 17) == '\n') {
186-
mod.remove_prefix(16);
187-
PX_ASSIGN_OR_RETURN(build_info, ReadModInfo(std::string(mod)));
188-
}
189-
190-
PX_ASSIGN_OR_RETURN(auto s, ExtractSemVer(std::string(go_version)));
191-
return std::make_pair(s, std::move(build_info));
192-
}
193-
194-
read_ptr_func_t read_ptr;
195-
switch (endianness) {
196-
case 0x0: {
197-
if (ptr_size == 4) {
198-
read_ptr = [&](u8string_view str_view) {
199-
return utils::LEndianBytesToInt<uint32_t, 4>(str_view);
200-
};
201-
} else if (ptr_size == 8) {
202-
read_ptr = [&](u8string_view str_view) {
203-
return utils::LEndianBytesToInt<uint64_t, 8>(str_view);
204-
};
205-
} else {
206-
return error::NotFound(absl::Substitute(
207-
"Binary reported pointer size=$0, refusing to parse non go binary", ptr_size));
186+
PX_ASSIGN_OR_RETURN(mod_info, binary_decoder.ExtractString(mod_size));
187+
} else {
188+
read_ptr_func_t read_ptr;
189+
switch (endianness) {
190+
case 0x0: {
191+
if (ptr_size == 4) {
192+
read_ptr = [&](u8string_view str_view) {
193+
return utils::LEndianBytesToInt<uint32_t, 4>(str_view);
194+
};
195+
} else if (ptr_size == 8) {
196+
read_ptr = [&](u8string_view str_view) {
197+
return utils::LEndianBytesToInt<uint64_t, 8>(str_view);
198+
};
199+
} else {
200+
return error::NotFound(absl::Substitute(
201+
"Binary reported pointer size=$0, refusing to parse non go binary", ptr_size));
202+
}
203+
break;
208204
}
209-
break;
210-
}
211-
case 0x1:
212-
if (ptr_size == 4) {
213-
read_ptr = [&](u8string_view str_view) {
214-
return utils::BEndianBytesToInt<uint64_t, 4>(str_view);
215-
};
216-
} else if (ptr_size == 8) {
217-
read_ptr = [&](u8string_view str_view) {
218-
return utils::BEndianBytesToInt<uint64_t, 8>(str_view);
219-
};
220-
} else {
221-
return error::NotFound(absl::Substitute(
222-
"Binary reported pointer size=$0, refusing to parse non go binary", ptr_size));
205+
case 0x1:
206+
if (ptr_size == 4) {
207+
read_ptr = [&](u8string_view str_view) {
208+
return utils::BEndianBytesToInt<uint64_t, 4>(str_view);
209+
};
210+
} else if (ptr_size == 8) {
211+
read_ptr = [&](u8string_view str_view) {
212+
return utils::BEndianBytesToInt<uint64_t, 8>(str_view);
213+
};
214+
} else {
215+
return error::NotFound(absl::Substitute(
216+
"Binary reported pointer size=$0, refusing to parse non go binary", ptr_size));
217+
}
218+
break;
219+
default: {
220+
auto msg =
221+
absl::Substitute("Invalid endianness=$0, refusing to parse non go binary", endianness);
222+
DCHECK(false) << msg;
223+
return error::NotFound(msg);
223224
}
224-
break;
225-
default: {
226-
auto msg =
227-
absl::Substitute("Invalid endianness=$0, refusing to parse non go binary", endianness);
228-
DCHECK(false) << msg;
229-
return error::NotFound(msg);
230225
}
231-
}
232226

233-
// Reads the virtual address location of the runtime.buildVersion symbol.
234-
PX_ASSIGN_OR_RETURN(auto runtime_version_vaddr,
235-
binary_decoder.ExtractString<u8string_view::value_type>(ptr_size));
236-
PX_ASSIGN_OR_RETURN(uint64_t ptr_addr,
237-
elf_reader->VirtualAddrToBinaryAddr(read_ptr(runtime_version_vaddr)));
227+
// Reads the virtual address location of the runtime.buildVersion symbol.
228+
PX_ASSIGN_OR_RETURN(auto runtime_version_vaddr,
229+
binary_decoder.ExtractString<u8string_view::value_type>(ptr_size));
230+
PX_ASSIGN_OR_RETURN(auto mod_info_vaddr,
231+
binary_decoder.ExtractString<u8string_view::value_type>(ptr_size));
232+
PX_ASSIGN_OR_RETURN(uint64_t ptr_addr,
233+
elf_reader->VirtualAddrToBinaryAddr(read_ptr(runtime_version_vaddr)));
238234

239-
PX_ASSIGN_OR_RETURN(auto version, ReadGoString(elf_reader, ptr_size, ptr_addr, read_ptr));
235+
PX_ASSIGN_OR_RETURN(go_version, ReadGoString(elf_reader, ptr_size, ptr_addr, read_ptr));
240236

241-
PX_ASSIGN_OR_RETURN(uint64_t mod_ptr_addr, elf_reader->VirtualAddrToBinaryAddr(
242-
read_ptr(runtime_version_vaddr) + ptr_size));
243-
auto mod_status = ReadGoString(elf_reader, ptr_size, mod_ptr_addr, read_ptr);
244-
if (mod_status.ok()) {
245-
std::string mod = mod_status.ValueOrDie();
246-
} else {
247-
LOG(WARNING) << "Failed to read mod status";
237+
auto mod_ptr_addr_s = elf_reader->VirtualAddrToBinaryAddr(read_ptr(mod_info_vaddr));
238+
if (mod_ptr_addr_s.ok()) {
239+
PX_ASSIGN_OR_RETURN(mod_info, ReadGoString(elf_reader, ptr_size,
240+
mod_ptr_addr_s.ConsumeValueOrDie(), read_ptr));
241+
}
242+
}
243+
244+
auto mod_size = mod_info.size();
245+
if (mod_size > 0) {
246+
// The module info string is delimited by the sentinel strings cmd/go/internal/modload.infoStart
247+
// and infoEnd. These strings are 16 characters long, so first check that the module info
248+
// contains more than the sentinel strings. This check reflects upstream's implementation
249+
// https://github.com/golang/go/blob/cb7a091d729eab75ccfdaeba5a0605f05addf422/src/debug/buildinfo/buildinfo.go#L214-L215
250+
if (mod_size >= 33 && mod_info.at(mod_size - 17) == '\n') {
251+
mod_info.erase(0, 16);
252+
PX_ASSIGN_OR_RETURN(build_info, ReadModInfo(mod_info));
253+
}
248254
}
249-
PX_ASSIGN_OR_RETURN(auto s, ExtractSemVer(std::string(version)));
255+
PX_ASSIGN_OR_RETURN(auto s, ExtractSemVer(go_version));
250256
return std::make_pair(s, std::move(build_info));
251257
}
252258

src/stirling/obj_tools/go_syms_test.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,14 @@ TEST(ReadGoBuildInfoTest, BuildinfoLittleEndiani386) {
176176
const std::string kPath = px::testing::BazelRunfilePath(kTestGoLittleEndiani386BinaryPath);
177177
ASSERT_OK_AND_ASSIGN(std::unique_ptr<ElfReader> elf_reader, ElfReader::Create(kPath));
178178
ASSERT_OK_AND_ASSIGN(auto pair, ReadGoBuildInfo(elf_reader.get()));
179+
179180
auto version = pair.first;
180181
EXPECT_THAT(version, StrEq("1.13.15"));
182+
183+
auto& buildinfo = pair.second;
184+
EXPECT_THAT(buildinfo.path, StrEq("command-line-arguments"));
185+
EXPECT_THAT(buildinfo.main.path, StrEq("px.dev/pixie"));
186+
EXPECT_THAT(buildinfo.main.version, StrEq("(devel)"));
181187
}
182188

183189
TEST(IsGoExecutableTest, WorkingOnBasicGoBinary) {

0 commit comments

Comments
 (0)