Skip to content

Commit a999d61

Browse files
committed
[Comgr] New API to map ELF virtual address to code object offsets
In this patch, we add a new Comgr API allowing a caller to map an ELF virtual address to a code object offset for a given executable. We also flag if the given address is in a NOBITS section, and the size of the current bits/nobits section. Change-Id: I304f1aad503a4de6a2c0db19fe55d77837851eb5
1 parent 2ab2251 commit a999d61

File tree

9 files changed

+439
-1
lines changed

9 files changed

+439
-1
lines changed

amd/comgr/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cmake_minimum_required(VERSION 3.13.4)
22

3-
project(amd_comgr VERSION "2.6.0" LANGUAGES C CXX)
3+
project(amd_comgr VERSION "2.7.0" LANGUAGES C CXX)
44
set(amd_comgr_NAME "${PROJECT_NAME}")
55

66
# Get git branch and commit hash to add to log for easier debugging.

amd/comgr/docs/ReleaseNotes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ New APIs
7979
name expression). These calls assume that names of interest have been
8080
enclosed the HIP runtime using a stub attribute containg the following
8181
string in the name: "__amdgcn_name_expr".
82+
- amd\_comgr\_map\_elf\_virtual\_address\_to\_code\_object\_offset() (v2.7)
83+
- For a given executable and ELF virtual address, return a code object
84+
offset. This API will benifet the ROCm debugger and profilier
85+
8286

8387
Deprecated APIs
8488
---------------

amd/comgr/include/amd_comgr.h.in

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,12 @@ extern "C" {
216216
*/
217217
#define AMD_COMGR_VERSION_2_6
218218

219+
/**
220+
* The function was introduced or changed in version 2.7 of the interface
221+
* and has the symbol version string of ``"@amd_comgr_NAME@_2.7"``.
222+
*/
223+
#define AMD_COMGR_VERSION_2_7
224+
219225
/** @} */
220226

221227
/**
@@ -2544,6 +2550,57 @@ amd_comgr_lookup_code_object(
25442550
amd_comgr_code_object_info_t *info_list,
25452551
size_t info_list_size) AMD_COMGR_VERSION_2_3;
25462552

2553+
/**
2554+
* @ brief Given a code object and an ELF virtual address, map the ELF virtual
2555+
* address to a code object offset. Also, determine if the ELF virtual address
2556+
* maps to an offset in a data region that is defined by the ELF file, but that
2557+
* does not occupy bytes in the ELF file. This is typically true of offsets that
2558+
* that refer to runtime or heap allocated memory. For ELF files with defined
2559+
* sections, these data regions are referred to as NOBITS or .bss sections.
2560+
*
2561+
* @param[in] data The data object to be inspected for the given ELF virtual
2562+
* address. This should be of kind AMD_COMGR_DATA_KIND_EXECUTABLE.
2563+
*
2564+
* @param[in] elf_virtual_address The address used to calculate the code object
2565+
* offset.
2566+
*
2567+
* @param[out] code_object_offset The code object offset returned to the caller
2568+
* based on the given ELF virtual address.
2569+
*
2570+
* @param[out] slice_size For nobits regions: the size in bytes, starting from
2571+
* the provided virtual address up to the end of the segment. In this case, the
2572+
* slice size represents the number of contiguous unreadable addresses following
2573+
* the provided address.
2574+
2575+
* For bits regions: the size in bytes, starting from the provided virtual
2576+
* address up to either the end of the segment, or the start of a NOBITS region.
2577+
* In this case, slice size represents the number of contiguous readable
2578+
* addresses following the provided address.
2579+
*
2580+
* @param[out] nobits Set to true if the code object offset points to a location
2581+
* in a data region that does not occupy bytes in the ELF file, as described
2582+
* above.
2583+
*
2584+
* @retval ::AMD_COMGR_STATUS_SUCCESS The function has been executed
2585+
* successfully.
2586+
*
2587+
* @retval ::AMD_COMGR_STATUS_ERROR The provided code object has an invalid
2588+
* header due to a mismatch in magic, class, data, version, abi, type, or
2589+
* machine.
2590+
*
2591+
* @retval ::AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT @p data is not of
2592+
* kind AMD_COMGR_DATA_KIND_EXECUTABLE or invalid, or that the provided @p
2593+
* elf_virtual_address is not within the ranges covered by the object's
2594+
* load-type program headers.
2595+
*/
2596+
amd_comgr_status_t AMD_COMGR_API
2597+
amd_comgr_map_elf_virtual_address_to_code_object_offset(
2598+
amd_comgr_data_t data,
2599+
uint64_t elf_virtual_address,
2600+
uint64_t *code_object_offset,
2601+
uint64_t *slice_size,
2602+
bool *nobits) AMD_COMGR_VERSION_2_7;
2603+
25472604
/** @} */
25482605

25492606
#ifdef __cplusplus

amd/comgr/src/comgr.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2230,3 +2230,81 @@ amd_comgr_status_t AMD_COMGR_API
22302230

22312231
return metadata::lookUpCodeObject(DataP, QueryList, QueryListSize);
22322232
}
2233+
2234+
amd_comgr_status_t AMD_COMGR_API
2235+
// NOLINTNEXTLINE(readability-identifier-naming)
2236+
amd_comgr_map_elf_virtual_address_to_code_object_offset(amd_comgr_data_t Data,
2237+
uint64_t ElfVirtualAddress,
2238+
uint64_t *CodeObjectOffset,
2239+
uint64_t *SliceSize,
2240+
bool *Nobits) {
2241+
2242+
DataObject *DataP = DataObject::convert(Data);
2243+
if (!DataP || !DataP->Data ||
2244+
(DataP->DataKind != AMD_COMGR_DATA_KIND_EXECUTABLE)) {
2245+
return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT;
2246+
}
2247+
2248+
// Create ELF Object file
2249+
auto ELFFileOrError = llvm::object::ELF64LEFile::create(
2250+
StringRef(DataP->Data, DataP->Size));
2251+
if (!ELFFileOrError) {
2252+
llvm::logAllUnhandledErrors(ELFFileOrError.takeError(),
2253+
llvm::errs(), "ELFObj creation error: ");
2254+
return AMD_COMGR_STATUS_ERROR;
2255+
}
2256+
auto ELFFile = std::move(ELFFileOrError.get());
2257+
2258+
// Error check the ELF file
2259+
auto ELFHeader = ELFFile.getHeader();
2260+
if (!ELFHeader.checkMagic())
2261+
return AMD_COMGR_STATUS_ERROR;
2262+
2263+
if (ELFHeader.e_ident[llvm::ELF::EI_CLASS] != llvm::ELF::ELFCLASS64 ||
2264+
ELFHeader.e_ident[llvm::ELF::EI_DATA] != llvm::ELF::ELFDATA2LSB ||
2265+
ELFHeader.e_ident[llvm::ELF::EI_VERSION] != llvm::ELF::EV_CURRENT ||
2266+
ELFHeader.e_ident[llvm::ELF::EI_OSABI] != llvm::ELF::ELFOSABI_AMDGPU_HSA)
2267+
return AMD_COMGR_STATUS_ERROR;
2268+
2269+
if (ELFHeader.e_ident[llvm::ELF::EI_ABIVERSION] !=
2270+
llvm::ELF::ELFABIVERSION_AMDGPU_HSA_V4 &&
2271+
ELFHeader.e_ident[llvm::ELF::EI_ABIVERSION] !=
2272+
llvm::ELF::ELFABIVERSION_AMDGPU_HSA_V5)
2273+
return AMD_COMGR_STATUS_ERROR;
2274+
2275+
if (ELFHeader.e_type != llvm::ELF::ET_DYN ||
2276+
ELFHeader.e_machine != llvm::ELF::EM_AMDGPU ||
2277+
ELFHeader.e_phoff == 0)
2278+
return AMD_COMGR_STATUS_ERROR;
2279+
2280+
// Access program headers
2281+
auto ProgHeadersOrError = ELFFile.program_headers();
2282+
if (!ProgHeadersOrError) {
2283+
llvm::logAllUnhandledErrors(ProgHeadersOrError.takeError(),
2284+
llvm::errs(), "ProgHeaders creation error: ");
2285+
return AMD_COMGR_STATUS_ERROR;
2286+
}
2287+
auto ProgHeaders = std::move(ProgHeadersOrError.get());
2288+
2289+
for (auto phdr : ProgHeaders) {
2290+
2291+
// Check if ELF virtual address defined in this header
2292+
if (phdr.p_type == llvm::ELF::PT_LOAD &&
2293+
ElfVirtualAddress >= phdr.p_vaddr &&
2294+
ElfVirtualAddress < phdr.p_vaddr + phdr.p_memsz) {
2295+
2296+
*CodeObjectOffset = ElfVirtualAddress - phdr.p_vaddr + phdr.p_offset;
2297+
*Nobits = ElfVirtualAddress - phdr.p_vaddr >= phdr.p_filesz;
2298+
2299+
if (*Nobits) // end of segment to relative address difference
2300+
*SliceSize = phdr.p_filesz - (ElfVirtualAddress - phdr.p_vaddr);
2301+
else // end of valid memory to relative address difference
2302+
*SliceSize = phdr.p_memsz - (ElfVirtualAddress - phdr.p_vaddr);
2303+
2304+
return AMD_COMGR_STATUS_SUCCESS;
2305+
}
2306+
}
2307+
2308+
// If the provided ELF virtual address is not mapped to an offset
2309+
return AMD_COMGR_STATUS_ERROR_INVALID_ARGUMENT;
2310+
}

amd/comgr/src/exportmap.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,7 @@ global: amd_comgr_populate_mangled_names;
7979
global: amd_comgr_populate_name_expression_map;
8080
amd_comgr_map_name_expression_to_symbol_name;
8181
} @amd_comgr_NAME@_2.5;
82+
83+
@amd_comgr_NAME@_2.7 {
84+
global: amd_comgr_map_elf_virtual_address_to_code_object_offset;
85+
} @amd_comgr_NAME@_2.6;

amd/comgr/test/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ configure_file("source/source1.s" "source/source1.s" COPYONLY)
8484
configure_file("source/source1.hip" "source/source1.hip" COPYONLY)
8585
configure_file("source/source2.hip" "source/source2.hip" COPYONLY)
8686
configure_file("source/name-expression.hip" "source/name-expression.hip" COPYONLY)
87+
configure_file("source/rocm56slice.b" "source/rocm56slice.b" COPYONLY)
88+
configure_file("source/rocm57slice.b" "source/rocm57slice.b" COPYONLY)
8789

8890
configure_file("source/square.hip" "source/square.hip" COPYONLY)
8991
configure_file("source/double.hip" "source/double.hip" COPYONLY)
@@ -177,6 +179,7 @@ add_comgr_test(mangled_names_test c)
177179
add_comgr_test(multithread_test cpp)
178180
add_comgr_test(name_expression_map_test c)
179181
add_comgr_test(nested_kernel_test c)
182+
add_comgr_test(map_elf_virtual_address_test c)
180183

181184
# Test : Compile HIP tests only if HIP-Clang is installed.
182185
if (DEFINED HIP_COMPILER AND "${HIP_COMPILER}" STREQUAL "clang")

0 commit comments

Comments
 (0)