This is an automated email from Gerrit. Florian Meister ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/5204
-- gerrit commit 6a010846b850b5ba5fb901d7a5dd266046d68a39 Author: Florian Meister <[email protected]> Date: Wed Jun 5 10:19:52 2019 +0200 target/image: allow loading of 64-bit ELF files Change-Id: I9b88edacf5ffcc3c1caeab8c426693de0d92a695 Signed-off-by: Florian Meister <[email protected]> diff --git a/src/target/image.c b/src/target/image.c index 9bd8f6b..9920311 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -11,6 +11,9 @@ * Copyright (C) 2009 by Franck Hereson * * [email protected] * * * + * Copyright (C) 2018 by Advantest * + * [email protected] * + * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * @@ -42,6 +45,10 @@ ((elf->endianness == ELFDATA2LSB) ? \ le_to_h_u32((uint8_t *)&field) : be_to_h_u32((uint8_t *)&field)) +#define field64(elf, field) \ + ((elf->endianness == ELFDATA2LSB) ? \ + le_to_h_u64((uint8_t *)&field) : be_to_h_u64((uint8_t *)&field)) + static int autodetect_image_type(struct image *image, const char *url) { int retval; @@ -49,7 +56,7 @@ static int autodetect_image_type(struct image *image, const char *url) size_t read_bytes; uint8_t buffer[9]; - /* read the first 4 bytes of image */ + /* read the first 9 bytes of image */ retval = fileio_open(&fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) return retval; @@ -66,8 +73,22 @@ static int autodetect_image_type(struct image *image, const char *url) /* check header against known signatures */ if (strncmp((char *)buffer, ELFMAG, SELFMAG) == 0) { - LOG_DEBUG("ELF image detected."); - image->type = IMAGE_ELF; + assert(EI_CLASS < 9); + switch(((char*) buffer)[EI_CLASS]) { + case ELFCLASS32: + LOG_DEBUG("ELF32 image detected."); + image->type = IMAGE_ELF32; + break; + + case ELFCLASS64: + LOG_DEBUG("ELF64 image detected."); + image->type = IMAGE_ELF64; + break; + + default: + LOG_ERROR("invalid ELF file, only 32/64bits files are supported"); + return ERROR_IMAGE_FORMAT_ERROR; + } } else if ((buffer[0] == ':') /* record start byte */ && (isxdigit(buffer[1])) && (isxdigit(buffer[2])) @@ -99,8 +120,10 @@ static int identify_image_type(struct image *image, const char *type_string, con image->type = IMAGE_BINARY; else if (!strcmp(type_string, "ihex")) image->type = IMAGE_IHEX; - else if (!strcmp(type_string, "elf")) - image->type = IMAGE_ELF; + else if (!strcmp(type_string, "elf32")) + image->type = IMAGE_ELF32; + else if (!strcmp(type_string, "elf64")) + image->type = IMAGE_ELF64; else if (!strcmp(type_string, "mem")) image->type = IMAGE_MEMORY; else if (!strcmp(type_string, "s19")) @@ -351,9 +374,9 @@ static int image_ihex_buffer_complete(struct image *image) return retval; } -static int image_elf_read_headers(struct image *image) +static int image_elf32_read_headers(struct image *image) { - struct image_elf *elf = image->type_private; + struct image_elf32 *elf = image->type_private; size_t read_bytes; uint32_t i, j; int retval; @@ -380,10 +403,6 @@ static int image_elf_read_headers(struct image *image) LOG_ERROR("invalid ELF file, bad magic number"); return ERROR_IMAGE_FORMAT_ERROR; } - if (elf->header->e_ident[EI_CLASS] != ELFCLASS32) { - LOG_ERROR("invalid ELF file, only 32bits files are supported"); - return ERROR_IMAGE_FORMAT_ERROR; - } elf->endianness = elf->header->e_ident[EI_DATA]; if ((elf->endianness != ELFDATA2LSB) @@ -477,27 +496,149 @@ static int image_elf_read_headers(struct image *image) return ERROR_OK; } -static int image_elf_read_section(struct image *image, +static int image_elf64_read_headers(struct image *image) +{ + struct image_elf64 *elf = image->type_private; + size_t read_bytes; + uint32_t i, j; + int retval; + uint32_t nload, load_to_vaddr = 0; + + elf->header = malloc(sizeof(Elf64_Ehdr)); + + if (elf->header == NULL) { + LOG_ERROR("insufficient memory to perform operation "); + return ERROR_FILEIO_OPERATION_FAILED; + } + + retval = fileio_read(elf->fileio, sizeof(Elf64_Ehdr), (uint8_t *)elf->header, &read_bytes); + if (retval != ERROR_OK) { + LOG_ERROR("cannot read ELF file header, read failed"); + return ERROR_FILEIO_OPERATION_FAILED; + } + if (read_bytes != sizeof(Elf64_Ehdr)) { + LOG_ERROR("cannot read ELF file header, only partially read"); + return ERROR_FILEIO_OPERATION_FAILED; + } + + if (strncmp((char *)elf->header->e_ident, ELFMAG, SELFMAG) != 0) { + LOG_ERROR("invalid ELF file, bad magic number"); + return ERROR_IMAGE_FORMAT_ERROR; + } + + elf->endianness = elf->header->e_ident[EI_DATA]; + if ((elf->endianness != ELFDATA2LSB) + && (elf->endianness != ELFDATA2MSB)) { + LOG_ERROR("invalid ELF file, unknown endianness setting"); + return ERROR_IMAGE_FORMAT_ERROR; + } + + elf->segment_count = field16(elf, elf->header->e_phnum); + if (elf->segment_count == 0) { + LOG_ERROR("invalid ELF file, no program headers"); + return ERROR_IMAGE_FORMAT_ERROR; + } + + retval = fileio_seek(elf->fileio, field64(elf, elf->header->e_phoff)); + if (retval != ERROR_OK) { + LOG_ERROR("cannot seek to ELF program header table, read failed"); + return retval; + } + + elf->segments = malloc(elf->segment_count*sizeof(Elf64_Phdr)); + if (elf->segments == NULL) { + LOG_ERROR("insufficient memory to perform operation "); + return ERROR_FILEIO_OPERATION_FAILED; + } + + retval = fileio_read(elf->fileio, elf->segment_count*sizeof(Elf64_Phdr), + (uint8_t *)elf->segments, &read_bytes); + if (retval != ERROR_OK) { + LOG_ERROR("cannot read ELF segment headers, read failed"); + return retval; + } + if (read_bytes != elf->segment_count*sizeof(Elf64_Phdr)) { + LOG_ERROR("cannot read ELF segment headers, only partially read"); + return ERROR_FILEIO_OPERATION_FAILED; + } + + /* count useful segments (loadable), ignore BSS section */ + image->num_sections = 0; + for (i = 0; i < elf->segment_count; i++) + if ((field32(elf, + elf->segments[i].p_type) == PT_LOAD) && + (field64(elf, elf->segments[i].p_filesz) != 0)) + image->num_sections++; + + assert(image->num_sections > 0); + + /** + * some ELF linkers produce binaries with *all* the program header + * p_paddr fields zero (there can be however one loadable segment + * that has valid physical address 0x0). + * If we have such a binary with more than + * one PT_LOAD header, then use p_vaddr instead of p_paddr + * (ARM ELF standard demands p_paddr = 0 anyway, and BFD + * library uses this approach to workaround zero-initialized p_paddrs + * when obtaining lma - look at elf.c of BDF) + */ + for (nload = 0, i = 0; i < elf->segment_count; i++) + if (elf->segments[i].p_paddr != 0) + break; + else if ((field32(elf, + elf->segments[i].p_type) == PT_LOAD) && + (field64(elf, elf->segments[i].p_memsz) != 0)) + ++nload; + + if (i >= elf->segment_count && nload > 1) + load_to_vaddr = 1; + + /* alloc and fill sections array with loadable segments */ + image->sections = malloc(image->num_sections * sizeof(struct imagesection)); + for (i = 0, j = 0; i < elf->segment_count; i++) { + if ((field32(elf, + elf->segments[i].p_type) == PT_LOAD) && + (field64(elf, elf->segments[i].p_filesz) != 0)) { + image->sections[j].size = field64(elf, elf->segments[i].p_filesz); + if (load_to_vaddr) + image->sections[j].base_address = field64(elf, + elf->segments[i].p_vaddr); + else + image->sections[j].base_address = field64(elf, + elf->segments[i].p_paddr); + image->sections[j].private = &elf->segments[i]; + image->sections[j].flags = field32(elf, elf->segments[i].p_flags); + j++; + } + } + + image->start_address_set = 1; + image->start_address = field64(elf, elf->header->e_entry); + + return ERROR_OK; +} + +static int image_elf32_read_section(struct image *image, int section, - uint32_t offset, + target_addr_t offset, uint32_t size, uint8_t *buffer, size_t *size_read) { - struct image_elf *elf = image->type_private; + struct image_elf32 *elf = image->type_private; Elf32_Phdr *segment = (Elf32_Phdr *)image->sections[section].private; size_t read_size, really_read; int retval; *size_read = 0; - LOG_DEBUG("load segment %d at 0x%" PRIx32 " (sz = 0x%" PRIx32 ")", section, offset, size); + LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size); /* read initialized data in current segment if any */ if (offset < field32(elf, segment->p_filesz)) { /* maximal size present in file for the current segment */ read_size = MIN(size, field32(elf, segment->p_filesz) - offset); - LOG_DEBUG("read elf: size = 0x%zu at 0x%" PRIx32 "", read_size, + LOG_DEBUG("read elf: size = 0x%zu at 0x%" TARGET_PRIxADDR "", read_size, field32(elf, segment->p_offset) + offset); /* read initialized area of the segment */ retval = fileio_seek(elf->fileio, field32(elf, segment->p_offset) + offset); @@ -520,6 +661,49 @@ static int image_elf_read_section(struct image *image, return ERROR_OK; } +static int image_elf64_read_section(struct image *image, + int section, + target_addr_t offset, + uint32_t size, + uint8_t *buffer, + size_t *size_read) +{ + struct image_elf64 *elf = image->type_private; + Elf64_Phdr *segment = (Elf64_Phdr *)image->sections[section].private; + size_t read_size, really_read; + int retval; + + *size_read = 0; + + LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size); + + /* read initialized data in current segment if any */ + if (offset < field64(elf, segment->p_filesz)) { + /* maximal size present in file for the current segment */ + read_size = MIN(size, field64(elf, segment->p_filesz) - offset); + LOG_DEBUG("read elf: size = 0x%zu at 0x%" TARGET_PRIxADDR "", read_size, + field64(elf, segment->p_offset) + offset); + /* read initialized area of the segment */ + retval = fileio_seek(elf->fileio, field64(elf, segment->p_offset) + offset); + if (retval != ERROR_OK) { + LOG_ERROR("cannot find ELF segment content, seek failed"); + return retval; + } + retval = fileio_read(elf->fileio, read_size, buffer, &really_read); + if (retval != ERROR_OK) { + LOG_ERROR("cannot read ELF segment content, read failed"); + return retval; + } + size -= read_size; + *size_read += read_size; + /* need more data ? */ + if (!size) + return ERROR_OK; + } + + return ERROR_OK; +} + static int image_mot_buffer_complete_inner(struct image *image, char *lpszLine, struct imagesection *section) @@ -768,18 +952,32 @@ int image_open(struct image *image, const char *url, const char *type_string) fileio_close(image_ihex->fileio); return retval; } - } else if (image->type == IMAGE_ELF) { - struct image_elf *image_elf; + } else if (image->type == IMAGE_ELF32) { + struct image_elf32 *image_elf32; - image_elf = image->type_private = malloc(sizeof(struct image_elf)); + image_elf32 = image->type_private = malloc(sizeof(struct image_elf32)); - retval = fileio_open(&image_elf->fileio, url, FILEIO_READ, FILEIO_BINARY); + retval = fileio_open(&image_elf32->fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) return retval; - retval = image_elf_read_headers(image); + retval = image_elf32_read_headers(image); if (retval != ERROR_OK) { - fileio_close(image_elf->fileio); + fileio_close(image_elf32->fileio); + return retval; + } + } else if (image->type == IMAGE_ELF64) { + struct image_elf64 *image_elf64; + + image_elf64 = image->type_private = malloc(sizeof(struct image_elf64)); + + retval = fileio_open(&image_elf64->fileio, url, FILEIO_READ, FILEIO_BINARY); + if (retval != ERROR_OK) + return retval; + + retval = image_elf64_read_headers(image); + if (retval != ERROR_OK) { + fileio_close(image_elf64->fileio); return retval; } } else if (image->type == IMAGE_MEMORY) { @@ -843,7 +1041,7 @@ int image_open(struct image *image, const char *url, const char *type_string) int image_read_section(struct image *image, int section, - uint32_t offset, + target_addr_t offset, uint32_t size, uint8_t *buffer, size_t *size_read) @@ -853,7 +1051,7 @@ int image_read_section(struct image *image, /* don't read past the end of a section */ if (offset + size > image->sections[section].size) { LOG_DEBUG( - "read past end of section: 0x%8.8" PRIx32 " + 0x%8.8" PRIx32 " > 0x%8.8" PRIx32 "", + "read past end of section: 0x%8.8" TARGET_PRIxADDR " + 0x%8.8" PRIx32 " > 0x%8.8" PRIx32 "", offset, size, image->sections[section].size); @@ -881,9 +1079,11 @@ int image_read_section(struct image *image, *size_read = size; return ERROR_OK; - } else if (image->type == IMAGE_ELF) - return image_elf_read_section(image, section, offset, size, buffer, size_read); - else if (image->type == IMAGE_MEMORY) { + } else if (image->type == IMAGE_ELF32) { + return image_elf32_read_section(image, section, offset, size, buffer, size_read); + } else if (image->type == IMAGE_ELF64) { + return image_elf64_read_section(image, section, offset, size, buffer, size_read); + } else if (image->type == IMAGE_MEMORY) { struct image_memory *image_memory = image->type_private; uint32_t address = image->sections[section].base_address + offset; @@ -936,7 +1136,7 @@ int image_read_section(struct image *image, return ERROR_OK; } -int image_add_section(struct image *image, uint32_t base, uint32_t size, int flags, uint8_t const *data) +int image_add_section(struct image *image, target_addr_t base, uint32_t size, int flags, uint8_t const *data) { struct imagesection *section; @@ -988,8 +1188,22 @@ void image_close(struct image *image) free(image_ihex->buffer); image_ihex->buffer = NULL; } - } else if (image->type == IMAGE_ELF) { - struct image_elf *image_elf = image->type_private; + } else if (image->type == IMAGE_ELF32) { + struct image_elf32 *image_elf = image->type_private; + + fileio_close(image_elf->fileio); + + if (image_elf->header) { + free(image_elf->header); + image_elf->header = NULL; + } + + if (image_elf->segments) { + free(image_elf->segments); + image_elf->segments = NULL; + } + } else if (image->type == IMAGE_ELF64) { + struct image_elf64 *image_elf = image->type_private; fileio_close(image_elf->fileio); diff --git a/src/target/image.h b/src/target/image.h index 9907a5f..2130cec 100644 --- a/src/target/image.h +++ b/src/target/image.h @@ -8,6 +8,9 @@ * Copyright (C) 2008 by Spencer Oliver * * [email protected] * * * + * Copyright (C) 2018 by Advantest * + * [email protected] * + * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * @@ -40,7 +43,8 @@ enum image_type { IMAGE_BINARY, /* plain binary */ IMAGE_IHEX, /* intel hex-record format */ IMAGE_MEMORY, /* target-memory pseudo-image */ - IMAGE_ELF, /* ELF binary */ + IMAGE_ELF32, /* 32-bit ELF binary */ + IMAGE_ELF64, /* 64-bit ELF binary */ IMAGE_SRECORD, /* motorola s19 */ IMAGE_BUILDER, /* when building a new image */ }; @@ -78,7 +82,7 @@ struct image_memory { uint32_t cache_address; }; -struct image_elf { +struct image_elf32 { struct fileio *fileio; Elf32_Ehdr *header; Elf32_Phdr *segments; @@ -86,17 +90,25 @@ struct image_elf { uint8_t endianness; }; +struct image_elf64 { + struct fileio *fileio; + Elf64_Ehdr *header; + Elf64_Phdr *segments; + uint32_t segment_count; + uint8_t endianness; +}; + struct image_mot { struct fileio *fileio; uint8_t *buffer; }; int image_open(struct image *image, const char *url, const char *type_string); -int image_read_section(struct image *image, int section, uint32_t offset, +int image_read_section(struct image *image, int section, target_addr_t offset, uint32_t size, uint8_t *buffer, size_t *size_read); void image_close(struct image *image); -int image_add_section(struct image *image, uint32_t base, uint32_t size, +int image_add_section(struct image *image, target_addr_t base, uint32_t size, int flags, uint8_t const *data); int image_calculate_checksum(uint8_t *buffer, uint32_t nbytes, -- _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
