35#include <unordered_map>
56enum class FuncmapEntryKind
66 FuncmapEntryKind kind{};
69 std::string source_loc{};
75 using EntryPtr = std::shared_ptr<const FuncmapEntry>;
77 std::vector<EntryPtr> entries{};
78 std::unordered_map<uint32_t, EntryPtr> by_id{};
79 uint32_t wave_size{0};
83 EntryPtr find(uint32_t marker_id)
const;
97parse_funcmap_section(std::string_view blob,
bool silent =
false);
102inline std::optional<std::string_view>
103extract_elf_section(
const char* elf_data,
size_t elf_size, std::string_view section_name);
108decode_marker_value(uint32_t v)
noexcept;
112inline Funcmap::EntryPtr
113Funcmap::find(uint32_t marker_id)
const
115 auto it = by_id.find(marker_id);
116 return (it == by_id.end()) ? nullptr : it->second;
120decode_marker_value(uint32_t v)
noexcept
122 return MarkerValue{v >> 2, bool((v >> 1) & 1u), bool(v & 1u)};
128emit_warning(
const std::string& msg,
size_t line_no,
bool silent)
131 std::cerr <<
"rocprofiler-sdk: .sqtt_funcmap warning";
132 if(line_no != 0) std::cerr <<
" (line " << line_no <<
')';
133 std::cerr <<
": " << msg <<
'\n';
136inline std::string_view
137rstrip_ws(std::string_view s)
noexcept
140 (s.back() ==
'\r' || s.back() ==
' ' || s.back() ==
'\t' || s.back() ==
'\0'))
147inline std::optional<std::pair<uint32_t, std::string_view>>
148split_id_payload(std::string_view payload)
150 size_t colon = payload.find(
':');
151 if(colon == std::string_view::npos)
return std::nullopt;
153 std::string_view id_str = payload.substr(0, colon);
154 std::string_view name_loc = payload.substr(colon + 1);
155 if(id_str.empty())
return std::nullopt;
160 if(c <
'0' || c >
'9')
return std::nullopt;
161 id =
id * 10 + uint64_t(c -
'0');
162 if(
id > 0xFFFFFFFFull)
return std::nullopt;
164 return std::make_pair(uint32_t(
id), name_loc);
167inline std::pair<std::string, std::string>
168split_name_loc(std::string_view name_loc)
170 size_t at = name_loc.find(
'@');
171 if(at == std::string_view::npos)
return {std::string(name_loc), std::string{}};
172 return {std::string(name_loc.substr(0, at)), std::string(name_loc.substr(at + 1))};
177parse_funcmap_section(std::string_view blob,
bool silent)
183 while(pos <= blob.size())
187 while(end < blob.size() && blob[end] !=
'\n' && blob[end] !=
'\0')
189 std::string_view line = detail::rstrip_ws(blob.substr(pos, end - pos));
193 if(end >= blob.size())
196 if(line.empty())
break;
203 if(line.empty())
continue;
206 if(line.size() < 2 || line[1] !=
':')
208 detail::emit_warning(
209 "malformed row (no prefix:): \"" + std::string(line) +
'"', line_no, silent);
213 char prefix = line[0];
214 std::string_view payload = line.substr(2);
217 [&](FuncmapEntryKind kind, uint32_t id, std::string name, std::string source_loc) {
218 auto entry = std::make_shared<FuncmapEntry>(
219 FuncmapEntry{kind, id, std::move(name), std::move(source_loc), 0});
220 out.entries.push_back(entry);
222 if(kind == FuncmapEntryKind::Kernel)
return;
224 auto inserted = out.by_id.emplace(
id, entry);
227 const auto& prev = inserted.first->second;
228 std::string msg =
"duplicate marker ID " + std::to_string(
id) +
229 " -- previous \"" + prev->name +
"\" replaced by \"" +
231 detail::emit_warning(msg, line_no, silent);
232 inserted.first->second = entry;
241 bool ok = !payload.empty();
242 for(
char c : payload)
244 if(c <
'0' || c >
'9')
249 w = w * 10 + uint64_t(c -
'0');
250 if(w > 0xFFFFFFFFull)
258 detail::emit_warning(
259 "malformed W: row: \"" + std::string(line) +
'"', line_no, silent);
263 out.wave_size = uint32_t(w);
269 auto [name, loc] = detail::split_name_loc(payload);
272 detail::emit_warning(
273 "K: row missing name: \"" + std::string(line) +
'"', line_no, silent);
276 record(FuncmapEntryKind::Kernel, 0, std::move(name), std::move(loc));
283 auto split = detail::split_id_payload(payload);
286 detail::emit_warning(std::string(
"malformed ") + prefix +
": row (bad ID): \"" +
287 std::string(line) +
'"',
292 auto [name, loc] = detail::split_name_loc(split->second);
295 detail::emit_warning(std::string(
"malformed ") + prefix +
296 ": row (empty name): \"" + std::string(line) +
'"',
301 FuncmapEntryKind kind = FuncmapEntryKind::Point;
303 kind = FuncmapEntryKind::Function;
304 else if(prefix ==
'U')
305 kind = FuncmapEntryKind::UserScope;
306 record(kind, split->first, std::move(name), std::move(loc));
311 detail::emit_warning(std::string(
"unknown row prefix '") + prefix +
"': \"" +
312 std::string(line) +
'"',
366inline std::optional<std::string_view>
367extract_elf_section(
const char* elf_data,
size_t elf_size, std::string_view section_name)
369 if(elf_data ==
nullptr || elf_size <
sizeof(Elf64_Ehdr))
return std::nullopt;
371 if(std::memcmp(elf_data, ELFMAG, SELFMAG) != 0)
return std::nullopt;
374 std::memcpy(&ehdr, elf_data,
sizeof(ehdr));
376 if(ehdr.e_ident[EI_CLASS] != ELFCLASS64)
return std::nullopt;
377 if(ehdr.e_shentsize !=
sizeof(Elf64_Shdr))
return std::nullopt;
378 if(ehdr.e_shoff == 0 || ehdr.e_shoff > elf_size)
return std::nullopt;
379 if(ehdr.e_shstrndx == SHN_UNDEF)
return std::nullopt;
382 uint64_t shdr_table_bytes = uint64_t(ehdr.e_shnum) *
sizeof(Elf64_Shdr);
383 if(shdr_table_bytes /
sizeof(Elf64_Shdr) != uint64_t(ehdr.e_shnum))
return std::nullopt;
385 if(shdr_table_bytes > uint64_t(elf_size) - ehdr.e_shoff)
return std::nullopt;
386 if(ehdr.e_shstrndx >= ehdr.e_shnum)
return std::nullopt;
389 auto read_shdr = [&](
unsigned idx) {
391 std::memcpy(&s, elf_data + ehdr.e_shoff + idx *
sizeof(Elf64_Shdr),
sizeof(Elf64_Shdr));
396 Elf64_Shdr shstr = read_shdr(ehdr.e_shstrndx);
397 if(shstr.sh_offset > elf_size || shstr.sh_size > uint64_t(elf_size) - shstr.sh_offset)
400 const char* str_base = elf_data + shstr.sh_offset;
401 size_t str_len = shstr.sh_size;
404 auto name_of = [&](uint32_t name_off) -> std::string_view {
405 if(name_off >= str_len)
return std::string_view{};
406 size_t end = name_off;
407 while(end < str_len && str_base[end] !=
'\0')
409 return std::string_view(str_base + name_off, end - name_off);
413 for(
unsigned i = 0; i < ehdr.e_shnum; ++i)
415 Elf64_Shdr s = read_shdr(i);
416 if(name_of(s.sh_name) != section_name)
continue;
419 if(s.sh_size == 0)
return std::nullopt;
420 if(s.sh_offset > elf_size || s.sh_size > uint64_t(elf_size) - s.sh_offset)
422 return std::string_view(elf_data + s.sh_offset, s.sh_size);