|  | // Copyright 2024 Google LLC | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #include "tests/verilator_sim/elf.h" | 
|  |  | 
|  | #include <cstring> | 
|  | #include <elf.h> | 
|  |  | 
|  | uint32_t LoadElf(uint8_t* data, CopyFn copy_fn) { | 
|  | const Elf32_Ehdr* elf_header = reinterpret_cast<Elf32_Ehdr*>(data); | 
|  | for (int i = 0; i < elf_header->e_phnum; ++i) { | 
|  | const Elf32_Phdr* program_header = reinterpret_cast<Elf32_Phdr*>( | 
|  | data + elf_header->e_phoff + sizeof(Elf32_Phdr) * i); | 
|  | if (program_header->p_type != PT_LOAD) { | 
|  | continue; | 
|  | } | 
|  | if (program_header->p_filesz == 0) { | 
|  | continue; | 
|  | } | 
|  | copy_fn(reinterpret_cast<void*>(program_header->p_paddr), | 
|  | reinterpret_cast<void*>(data + program_header->p_offset), | 
|  | program_header->p_filesz); | 
|  | } | 
|  | return elf_header->e_entry; | 
|  | } | 
|  |  | 
|  | bool LookupSymbol(const uint8_t* data, const std::string& symbol_name, uint32_t* symbol_addr) { | 
|  | if (symbol_addr == nullptr) | 
|  | return false; | 
|  | const Elf32_Ehdr* elf_header = reinterpret_cast<const Elf32_Ehdr*>(data); | 
|  |  | 
|  | // Locate .shstrtab | 
|  | if (elf_header->e_shstrndx == SHN_UNDEF) | 
|  | return false; | 
|  | const Elf32_Half section_string_table_idx = elf_header->e_shstrndx; | 
|  | const Elf32_Shdr* section_string_table_header = reinterpret_cast<const Elf32_Shdr*>( | 
|  | data + elf_header->e_shoff + sizeof(Elf32_Shdr) * section_string_table_idx); | 
|  | const char* section_string_table = | 
|  | reinterpret_cast<const char*>(data + section_string_table_header->sh_offset); | 
|  |  | 
|  | // Locate .strtab and .symtab | 
|  | const Elf32_Sym* symbol_table = nullptr; | 
|  | uint32_t symbol_count; | 
|  | const char* string_table = nullptr; | 
|  | for (int i = 0; i < elf_header->e_shnum; ++i) { | 
|  | const Elf32_Shdr* section_header = reinterpret_cast<const Elf32_Shdr*>( | 
|  | data + elf_header->e_shoff + sizeof(Elf32_Shdr) * i); | 
|  | if (section_header->sh_type == SHT_SYMTAB) { | 
|  | const char* symtab_name = (section_string_table + section_header->sh_name); | 
|  | const char* expected_symtab_name = ".symtab"; | 
|  | if (strncmp(symtab_name, expected_symtab_name, strlen(expected_symtab_name)) == 0) { | 
|  | symbol_count = section_header->sh_size / sizeof(Elf32_Sym); | 
|  | symbol_table = reinterpret_cast<const Elf32_Sym*>( | 
|  | data + section_header->sh_offset); | 
|  | } | 
|  | } | 
|  | if (section_header->sh_type == SHT_STRTAB) { | 
|  | const char* strtab_name = (section_string_table + section_header->sh_name); | 
|  | const char* expected_strtab_name = ".strtab"; | 
|  | if (strncmp(strtab_name, expected_strtab_name, strlen(expected_strtab_name)) == 0) { | 
|  | string_table = reinterpret_cast<const char*>(data + section_header->sh_offset); | 
|  | } | 
|  | } | 
|  | } | 
|  | if (string_table == nullptr || symbol_table == nullptr) | 
|  | return false; | 
|  |  | 
|  | // Find our symbol! | 
|  | for (uint32_t i = 0; i < symbol_count; ++i) { | 
|  | const Elf32_Sym* symbol = symbol_table + i; | 
|  | if (symbol->st_name != 0) { | 
|  | const char* found_symbol_name = string_table + symbol->st_name; | 
|  | if (strncmp(found_symbol_name, symbol_name.c_str(), symbol_name.length()) == 0) { | 
|  | *symbol_addr = symbol->st_value; | 
|  | return true; | 
|  | } | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } |