ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
emu_elf_symbols.c
Go to the documentation of this file.
1
12
13#include <stddef.h>
14#include <stdint.h>
15#include <string.h>
16
17#include "emu_elf.h"
19
30
32typedef struct {
33 uint32_t offset;
34 uint16_t entry_size;
35 uint16_t count;
37
39typedef struct {
40 uint32_t symbol_offset;
41 uint32_t symbol_count;
42 uint32_t entry_size;
43 uint32_t string_offset;
44 uint32_t string_size;
46
60RA8_INTERNAL static uint16_t internal_symbol_u16(const uint8_t* bytes)
61{
62 return (uint16_t)((uint16_t)bytes[0] | ((uint16_t)bytes[1] << 8U));
63}
64
78RA8_INTERNAL static uint32_t internal_symbol_u32(const uint8_t* bytes)
79{
80 return (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8U) | ((uint32_t)bytes[2] << 16U) |
81 ((uint32_t)bytes[3] << k_elf_word_high_shift);
82}
83
101RA8_INTERNAL static bool
102internal_symbol_read(const emu_elf_source_t* elf, uint64_t offset, uint8_t* bytes, size_t length)
103{
104 emu_elf_view_t view = {};
105 return priv_emu_elf_read(elf, offset, length, bytes, length, &view).status == k_emu_elf_io_ok;
106}
107
125{
126 uint8_t bytes[k_elf_ehdr_size] = {};
127 if (!internal_symbol_read(elf, 0U, bytes, sizeof(bytes)) ||
128 (memcmp(bytes,
129 "\x7F"
130 "ELF",
131 4U) != 0) ||
132 (bytes[4] != 1U) || (bytes[k_elf_data_offset] != 1U)) {
133 return false;
134 }
135 const emu_elf_section_table_t decoded = {
136 .offset = internal_symbol_u32(&bytes[32]),
137 .entry_size = internal_symbol_u16(&bytes[k_elf_shentsize_offset]),
139 };
140 const uint64_t table_bytes = (uint64_t)decoded.entry_size * decoded.count;
141 if ((decoded.offset == 0U) || (decoded.entry_size < k_elf_shentsize_min) ||
142 ((uint64_t)decoded.offset > elf->length) || (table_bytes > (elf->length - decoded.offset))) {
143 return false;
144 }
145 *table = decoded;
146 return true;
147}
148
167 const emu_elf_section_table_t* sections,
168 uint32_t index,
169 uint8_t bytes[k_elf_shentsize_min])
170{
171 const uint64_t offset = (uint64_t)sections->offset + ((uint64_t)index * sections->entry_size);
172 return internal_symbol_read(elf, offset, bytes, k_elf_shentsize_min);
173}
174
193 const emu_elf_section_table_t* sections,
194 const uint8_t bytes[k_elf_shentsize_min],
196{
197 const uint32_t type = internal_symbol_u32(&bytes[4]);
198 const uint32_t symbol_off = internal_symbol_u32(&bytes[16]);
199 const uint32_t symbol_sz = internal_symbol_u32(&bytes[k_elf_sh_size_off]);
200 const uint32_t link = internal_symbol_u32(&bytes[k_elf_sh_link_off]);
201 const uint32_t entry_sz = internal_symbol_u32(&bytes[k_elf_sh_entsize_off]);
202 if ((type != k_elf_sht_symtab) || (entry_sz < k_elf_symbol_entry_min) ||
203 (link >= sections->count) || ((uint64_t)symbol_off > elf->length) ||
204 ((uint64_t)symbol_sz > (elf->length - symbol_off))) {
205 return false;
206 }
207 uint8_t strings[k_elf_shentsize_min] = {};
208 if (!internal_section_read(elf, sections, link, strings)) {
209 return false;
210 }
211 const uint32_t string_off = internal_symbol_u32(&strings[16]);
212 const uint32_t string_sz = internal_symbol_u32(&strings[k_elf_sh_size_off]);
213 if (((uint64_t)string_off > elf->length) || ((uint64_t)string_sz > (elf->length - string_off))) {
214 return false;
215 }
216 *table = (emu_elf_symbol_table_t){
217 .symbol_offset = symbol_off,
218 .symbol_count = symbol_sz / entry_sz,
219 .entry_size = entry_sz,
220 .string_offset = string_off,
221 .string_size = string_sz,
222 };
223 return true;
224}
225
245 const emu_elf_symbol_table_t* table,
247 void* ctx,
248 uint32_t* visited)
249{
250 for (uint32_t index = 0U; index < table->symbol_count; index++) {
251 uint8_t bytes[k_elf_symbol_entry_min] = {};
252 const uint64_t offset = (uint64_t)table->symbol_offset + ((uint64_t)index * table->entry_size);
253 if (!internal_symbol_read(elf, offset, bytes, sizeof(bytes))) {
254 return false;
255 }
256 const uint32_t relative_name = internal_symbol_u32(bytes);
257 if (relative_name >= table->string_size) {
258 continue;
259 }
260 const emu_elf_symbol_t symbol = {
261 .name_offset = (uint64_t)table->string_offset + relative_name,
262 .value = internal_symbol_u32(&bytes[4]),
263 .size = internal_symbol_u32(&bytes[8]),
264 .info = bytes[k_elf_sym_info_off],
265 };
266 (*visited)++;
267 if (!fn(&symbol, ctx)) {
268 return false;
269 }
270 }
271 return true;
272}
273
274uint32_t elf_foreach_symbol(const emu_elf_source_t* elf, emu_elf_symbol_fn fn, void* ctx)
275{
276 if ((elf == nullptr) || (fn == nullptr)) {
277 return 0U;
278 }
279 emu_elf_section_table_t sections = {};
280 if (!internal_section_table(elf, &sections)) {
281 return 0U;
282 }
283 uint32_t visited = 0U;
284 for (uint32_t index = 0U; index < sections.count; index++) {
285 uint8_t bytes[k_elf_shentsize_min] = {};
286 emu_elf_symbol_table_t table = {};
287 if (!internal_section_read(elf, &sections, index, bytes) ||
288 !internal_symbol_table(elf, &sections, bytes, &table)) {
289 continue;
290 }
291 if (!internal_symbol_walk(elf, &table, fn, ctx, &visited)) {
292 break;
293 }
294 }
295 return visited;
296}
297
299 uint64_t offset,
301 void* ctx)
302{
303 if ((elf == nullptr) || (fn == nullptr) || ((uint64_t)offset >= elf->length)) {
304 return false;
305 }
306 uint8_t bytes[k_elf_string_chunk];
307 uint64_t cursor = offset;
308 while (cursor < elf->length) {
309 const uint64_t remaining = elf->length - cursor;
310 const size_t chunk = (remaining < sizeof(bytes)) ? (size_t)remaining : sizeof(bytes);
311 if (!internal_symbol_read(elf, cursor, bytes, chunk)) {
312 return false;
313 }
314 const uint8_t* const end = (const uint8_t*)memchr(bytes, 0, chunk);
315 const size_t length = (end == nullptr) ? chunk : (size_t)(end - bytes);
316 if ((length > 0U) && !fn((const char*)bytes, length, ctx)) {
317 return false;
318 }
319 if (end != nullptr) {
320 return true;
321 }
322 cursor += chunk;
323 }
324 return false;
325}
326
328typedef struct {
329 const char* expected;
330 size_t length;
331 size_t compared;
332 bool equal;
334
351RA8_INTERNAL static bool internal_name_chunk(const char* bytes, size_t length, void* opaque)
352{
353 emu_elf_name_match_t* const match = (emu_elf_name_match_t*)opaque;
354 if ((length > (match->length - match->compared)) ||
355 (memcmp(bytes, &match->expected[match->compared], length) != 0)) {
356 match->equal = false;
357 return false;
358 }
359 match->compared += length;
360 return true;
361}
362
364typedef struct {
366 const char* name;
367 size_t length;
368 uint32_t address;
369 uint32_t size;
371
387RA8_INTERNAL static bool internal_lookup_symbol(const emu_elf_symbol_t* symbol, void* opaque)
388{
389 emu_elf_lookup_t* const lookup = (emu_elf_lookup_t*)opaque;
390 emu_elf_name_match_t match = {.expected = lookup->name, .length = lookup->length, .equal = true};
391 const bool complete =
392 elf_string_foreach(lookup->source, symbol->name_offset, internal_name_chunk, &match);
393 if (!complete || !match.equal || (match.compared != match.length)) {
394 return true;
395 }
396 lookup->address = symbol->value & ~1U;
397 lookup->size = symbol->size;
398 return false;
399}
400
401uint32_t elf_sym_addr(const emu_elf_source_t* elf, const char* name, uint32_t* size_out)
402{
403 if (size_out != nullptr) {
404 *size_out = 0U;
405 }
406 if ((elf == nullptr) || (name == nullptr)) {
407 return 0U;
408 }
409 emu_elf_lookup_t lookup = {.source = elf, .name = name, .length = strlen(name)};
410 (void)elf_foreach_symbol(elf, internal_lookup_symbol, &lookup);
411 if ((lookup.address != 0U) && (size_out != nullptr)) {
412 *size_out = lookup.size;
413 }
414 return lookup.address;
415}
@ k_elf_data_offset
ELF identification data-byte offset.
Definition emu_elf.c:27
@ k_elf_word_high_shift
Shift of byte three in a word.
Definition emu_elf.c:26
ELF32 image services for the board emulator (load / symbols / vectors).
bool(* emu_elf_string_fn)(const char *bytes, size_t length, void *ctx)
Callback receiving one non-empty chunk of an ELF string.
Definition emu_elf.h:335
@ k_elf_shentsize_min
ELF32 section-header entry size.
Definition emu_elf.h:65
@ k_elf_sh_entsize_off
sh_entsize in a section header.
Definition emu_elf.h:68
@ k_elf_sym_info_off
st_info in a symbol-table entry.
Definition emu_elf.h:69
@ k_elf_sh_link_off
sh_link in a section header.
Definition emu_elf.h:67
@ k_elf_ehdr_size
ELF32 file-header size.
Definition emu_elf.h:52
@ k_elf_sh_size_off
sh_size in a section header.
Definition emu_elf.h:66
bool(* emu_elf_symbol_fn)(const emu_elf_symbol_t *symbol, void *ctx)
Callback invoked for each bounds-checked ELF symbol entry.
Definition emu_elf.h:315
@ k_emu_elf_io_ok
The complete operation succeeded.
Definition emu_elf.h:75
Private raw-descriptor ELF source operations.
emu_elf_io_result_t priv_emu_elf_read(const emu_elf_source_t *source, uint64_t offset, size_t required_bytes, void *scratch, size_t supplied_bytes, emu_elf_view_t *view)
Read one exact source range into caller-owned bounded scratch.
bool elf_string_foreach(const emu_elf_source_t *elf, uint64_t offset, emu_elf_string_fn fn, void *ctx)
Stream one NUL-terminated ELF string through bounded stack chunks.
static RA8_INTERNAL bool internal_section_table(const emu_elf_source_t *elf, emu_elf_section_table_t *table)
Decode and validate section-header table geometry.
static RA8_INTERNAL bool internal_symbol_walk(const emu_elf_source_t *elf, const emu_elf_symbol_table_t *table, emu_elf_symbol_fn fn, void *ctx, uint32_t *visited)
Walk every entry of one validated symbol table.
static RA8_INTERNAL bool internal_lookup_symbol(const emu_elf_symbol_t *symbol, void *opaque)
Compare one symbol name and stop on an exact hit.
uint32_t elf_sym_addr(const emu_elf_source_t *elf, const char *name, uint32_t *size_out)
Resolve a function symbol's entry address from the ELF .symtab.
static RA8_INTERNAL bool internal_section_read(const emu_elf_source_t *elf, const emu_elf_section_table_t *sections, uint32_t index, uint8_t bytes[k_elf_shentsize_min])
Read one section header from validated table geometry.
emu_elf_symbol_limit_t
Fixed bytes consumed from section and symbol entries.
@ k_elf_string_chunk
Transient streamed-name bytes.
@ k_elf_symbol_entry_min
ELF32 symbol bytes consumed.
@ k_elf_section_count_offset
Section-count header offset.
@ k_elf_sht_symtab
SHT_SYMTAB section type.
@ k_elf_shentsize_offset
Section-entry-size header offset.
static RA8_INTERNAL uint16_t internal_symbol_u16(const uint8_t *bytes)
Decode one little-endian 16-bit field.
static RA8_INTERNAL bool internal_symbol_table(const emu_elf_source_t *elf, const emu_elf_section_table_t *sections, const uint8_t bytes[k_elf_shentsize_min], emu_elf_symbol_table_t *table)
Decode one SHT_SYMTAB and its linked string-table bounds.
uint32_t elf_foreach_symbol(const emu_elf_source_t *elf, emu_elf_symbol_fn fn, void *ctx)
Walk every symbol in every usable SHT_SYMTAB section.
static RA8_INTERNAL uint32_t internal_symbol_u32(const uint8_t *bytes)
Decode one little-endian 32-bit field without alignment assumptions.
static RA8_INTERNAL bool internal_name_chunk(const char *bytes, size_t length, void *opaque)
Compare one streamed source-name chunk with the expected suffix.
static RA8_INTERNAL bool internal_symbol_read(const emu_elf_source_t *elf, uint64_t offset, uint8_t *bytes, size_t length)
Read one fixed-size source object into supplied scratch.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
void * memchr(const void *s, int c, size_t n)
Locate a byte in a memory area.
int memcmp(const void *a, const void *b, size_t n)
Compare bytes in two memory areas.
size_t strlen(const char *s)
Calculate string length.
emu_elf_io_status_t status
Semantic completion status.
Definition emu_elf.h:84
Symbol-address lookup callback state.
size_t length
Expected name length.
const char * name
Expected symbol name.
uint32_t size
Resolved symbol size.
uint32_t address
Resolved Thumb-cleared value.
const emu_elf_source_t * source
Open source for name streaming.
Incremental exact string comparison state.
const char * expected
Expected NUL-terminated name.
size_t compared
Bytes compared so far.
bool equal
Sticky exact-prefix equality.
size_t length
Expected length excluding NUL.
Decoded section-header table geometry.
uint16_t count
Section-header entry count.
uint32_t offset
First section-header file offset.
uint16_t entry_size
Bytes per section-header entry.
One independently owned immutable raw-descriptor ELF source.
Definition emu_elf.h:91
uint64_t length
Stat-derived parsing bound.
Definition emu_elf.h:93
One bounds-checked symbol-table entry plus its string offset.
Definition emu_elf.h:307
uint64_t name_offset
Absolute source offset of the NUL-terminated name.
Definition emu_elf.h:308
uint32_t size
Symbol byte extent.
Definition emu_elf.h:310
uint32_t value
Symbol value.
Definition emu_elf.h:309
Decoded usable symbol/string table pair.
uint32_t string_offset
Linked string-table file offset.
uint32_t symbol_count
Number of whole symbol entries.
uint32_t entry_size
Bytes per symbol entry.
uint32_t string_size
Linked string-table byte count.
uint32_t symbol_offset
First symbol entry file offset.
Transient view into caller-owned bounded scratch.
Definition emu_elf.h:97