Add changes to get custom section data from xrt::elf#9664
Add changes to get custom section data from xrt::elf#9664rbramand-xilinx wants to merge 1 commit intoXilinx:masterfrom
Conversation
Signed-off-by: rahul <rbramand@amd.com>
|
clang-tidy review says "All clean, LGTM! 👍" |
There was a problem hiding this comment.
Pull request overview
Adds public APIs to retrieve custom ELF section data from xrt::elf at global, kernel, and kernel-instance scope, and wires up parsing/storage of those custom sections in the ELF runtime implementation.
Changes:
- Added
get_custom_section()APIs onxrt::elf,xrt::elf::kernel, andxrt::elf::kernel::instancereturningxrt::detail::span<const char>. - Implemented parsing of custom sections (SHT_LOUSER + 1) and routing of section data into global/kernel/instance maps.
- Refactored ELF parsing entry point from
.group-only parsing to a unifiedparse_sections()flow.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 9 comments.
| File | Description |
|---|---|
src/runtime_src/core/include/xrt/experimental/xrt_elf.h |
Exposes new public APIs (and doxygen) for retrieving custom section data at multiple scopes. |
src/runtime_src/core/common/api/xrt_elf.cpp |
Implements storage and lookup for custom sections, plus parsing changes to collect and classify custom sections. |
src/runtime_src/core/common/api/elf_int.h |
Adds internal storage for global custom sections and declares new parsing helpers / accessor. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Get custom section data by name | ||
| // Returns span of custom section data | ||
| detail::span<const char> | ||
| get_custom_section(const std::string& name); |
There was a problem hiding this comment.
elf_impl::get_custom_section() is a read-only accessor but is declared/defined non-const. Making it const would better match the rest of the getter-style API, allow calling it on const elf_impl, and communicate that it does not mutate internal state.
| get_custom_section(const std::string& name); | |
| get_custom_section(const std::string& name) const; |
| // Map for custom sections of an instance | ||
| // key - custom section name, value - custom section data | ||
| std::map<std::string, detail::span<const char>> m_custom_section_map; |
There was a problem hiding this comment.
instance_impl also stores custom section data as detail::span<const char>, which is a non-owning view into elf_impl::m_elfio section memory. Since xrt::elf::kernel::instance objects can be copied out and outlive the parent xrt::elf, instance::get_custom_section() can return a dangling span after the xrt::elf is destroyed. Please change storage to an owning representation (or a safe indirection back to elf_impl with lifetime checks) so the returned span never references freed memory.
| for (auto& kernel : m_kernels) { | ||
| if (kernel.get_name() != kernel_name) | ||
| continue; | ||
|
|
||
| if (instance_name.empty()) { | ||
| kernel.get_handle()->add_custom_section(sec_name, data); | ||
| return; | ||
| } | ||
|
|
||
| for (auto& instance : kernel.get_instances()) { | ||
| if (instance.get_name() != instance_name) | ||
| continue; | ||
|
|
||
| instance.get_handle()->add_custom_section(sec_name, data); | ||
| return; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
add_custom_section_to_kernel_or_instance() silently does nothing if the specified kernel/instance name is not found. That can make malformed/unsupported ELFs look like they simply have no custom sections, which is hard to debug and can lead to incorrect behavior. Consider returning a bool and having the caller throw with a clear error when the kernel/instance cannot be located (or at least log/trace the drop).
| for (auto& instance : kernel.get_instances()) { | ||
| if (instance.get_name() != instance_name) | ||
| continue; | ||
|
|
||
| instance.get_handle()->add_custom_section(sec_name, data); | ||
| return; |
There was a problem hiding this comment.
The inner loop for (auto& instance : kernel.get_instances()) iterates over a temporary vector because kernel_impl::get_instances() returns by value. This copies the entire instance list for every custom section being attached, which can be unnecessarily expensive. Consider iterating the stored instances without copying (e.g., add a get_instances_ref() on kernel_impl, or expose a helper on kernel_impl to add a custom section by instance name).
|
|
||
| // collect custom sections and parse .group sections to populate maps | ||
| std::vector<uint32_t> custom_section_ids; | ||
| auto CUSTOM_SECTION_TYPE = ELFIO::SHT_LOUSER + 1; |
There was a problem hiding this comment.
CUSTOM_SECTION_TYPE is effectively a constant but is declared as a mutable auto variable with ALL_CAPS naming. Consider making it constexpr (and giving it an explicit ELFIO type) to document intent and avoid accidental modification.
| auto CUSTOM_SECTION_TYPE = ELFIO::SHT_LOUSER + 1; | |
| constexpr ELFIO::Elf_Word CUSTOM_SECTION_TYPE = ELFIO::SHT_LOUSER + 1; |
| /** | ||
| * get_custom_section() - Get Global custom section data from ELF | ||
| * | ||
| * @param section_name | ||
| * Name of the custom section | ||
| * | ||
| * @return | ||
| * A span representing the custom section data | ||
| * | ||
| * @note | ||
| * Returns xrt::detail::span (lightweight span) for now. Will switch to | ||
| * std::span when XRT uses C++20 by default. | ||
| */ | ||
| XRT_API_EXPORT | ||
| xrt::detail::span<const char> | ||
| get_custom_section(const std::string& section_name) const; |
There was a problem hiding this comment.
The new APIs return a non-owning xrt::detail::span into ELF section storage, but the doxygen comment doesn’t specify the required lifetime (e.g., whether the returned view is only valid while the originating xrt::elf object remains alive). Please document the lifetime/ownership guarantees explicitly so callers don’t accidentally keep and use the span after the backing ELF data is destroyed.
| /** | ||
| * get_custom_section() - Get custom section data of an instance from ELF | ||
| * | ||
| * @param section_name | ||
| * Name of the custom section | ||
| * | ||
| * @return | ||
| * A span representing the custom section data | ||
| * | ||
| * @note | ||
| * Returns xrt::detail::span (lightweight span) for now. Will switch to | ||
| * std::span when XRT uses C++20 by default. | ||
| */ | ||
| XRT_API_EXPORT | ||
| xrt::detail::span<const char> | ||
| get_custom_section(const std::string& section_name) const; |
There was a problem hiding this comment.
kernel::instance::get_custom_section() returns a non-owning span, but the comment doesn’t state how long the returned view remains valid (what object owns the backing bytes). Please document the lifetime/ownership guarantees explicitly to prevent callers from using a span after the backing ELF storage has been released.
There was a problem hiding this comment.
This is a valid point. At least state that the span is valid only as long as the xrt::elf is in scope.
| /** | ||
| * get_custom_section() - Get custom section data of a kernel from ELF | ||
| * | ||
| * @param section_name | ||
| * Name of the custom section | ||
| * | ||
| * @return | ||
| * A span representing the custom section data | ||
| * | ||
| * @note | ||
| * Returns xrt::detail::span (lightweight span) for now. Will switch to | ||
| * std::span when XRT uses C++20 by default. | ||
| */ | ||
| XRT_API_EXPORT | ||
| xrt::detail::span<const char> | ||
| get_custom_section(const std::string& section_name) const; |
There was a problem hiding this comment.
kernel::get_custom_section() returns a non-owning span but the doxygen does not describe lifetime/ownership of the returned data. Please add an explicit lifetime note (e.g., valid while the originating ELF object and its backing storage remain alive) so callers know whether they must copy the data before storing it.
| // Map for custom sections of a kernel | ||
| // key - custom section name, value - custom section data | ||
| std::map<std::string, detail::span<const char>> m_custom_section_map; | ||
|
|
There was a problem hiding this comment.
kernel_impl stores custom section data as detail::span<const char> in m_custom_section_map. The span points into ELFIO::section data owned by elf_impl::m_elfio, but xrt::elf::kernel objects can outlive the parent xrt::elf (they hold independent shared_ptr<kernel_impl>). This makes kernel::get_custom_section() able to return a dangling view (use-after-free) once the parent xrt::elf is destroyed. Consider storing an owning buffer for each custom section (e.g., std::vector<char>/shared buffer) or redesigning so kernel_impl/instance_impl retain safe access to the backing ELF data without creating ownership cycles (e.g., keep indices + weak_ptr to elf_impl and fail if expired).
Problem solved by the commit
Added changes as per spec - https://amd.atlassian.net/wiki/spaces/AIE/pages/1341720313/Spec+of+xrt+elf+APIs to get custom section data from xrt::elf object.
Custom section can be global level (not associated with any kernel/compute unit), kernel level and instance level. Added apis in respective classes to get the data.
Bug / issue (if any) fixed, which PR introduced the bug, how it was discovered
It is a new feature
How problem was solved, alternative solutions (if any) and why they were rejected
Added public API get_custom_section in xrt::elf class to get global custom section data, in xrt::elf::kernel class to get kernel custom section data and in xrt::elf::kernel::instance class to get instance custom section data
The return type for all these API's is xrt::detail::span. Ideally it should be std::span but as XRT uses c++17 and std::span is available from c++20, we are using a lightweight span class implemented in XRT. Move to std::span when XRT moves to c++ 20
Risks (if any) associated the changes in the commit
Low
What has been tested and how, request additional testing if necessary
Tested using full ELF with custom sections and retrieving both text and binary custom section data works as expected
Documentation impact (if any)
Added doxygen comments wherever needed.
Example showing how to retrieve custom section data :
1. Global-level custom section
Custom sections that are not tied to any kernel or instance are read from the xrt::elf object:
2. Kernel-level custom section
Sections attached to a kernel (not to a specific instance) are read from the corresponding xrt::elf::kernel:
3. Instance-level custom section
Sections attached to a specific kernel instance are read from the corresponding xrt::elf::kernel::instance: