From 681a66e1273151577414c74af6c8ff1a25944178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sat, 17 Dec 2022 19:15:45 +0100 Subject: [PATCH 01/18] Start XML export functiionality --- CMakeLists.txt | 7 +++- include/patchelfcrc/elfpatch.h | 13 ++++++ include/patchelfcrc/xml.h | 14 +++++++ src/elfpatch.c | 29 +++++++++++++ src/main.c | 47 ++++++++++++++++++--- src/xml.c | 74 ++++++++++++++++++++++++++++++++++ 6 files changed, 177 insertions(+), 7 deletions(-) create mode 100644 include/patchelfcrc/xml.h create mode 100644 src/xml.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c9c9a7..5b65ccb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ find_package(PkgConfig REQUIRED) pkg_check_modules(ELF REQUIRED libelf) find_package(Doxygen) +find_package(LibXml2 REQUIRED) add_subdirectory(man) @@ -47,9 +48,11 @@ set(FORT_ENABLE_TESTING OFF CACHE INTERNAL "") add_subdirectory(3rdparty/libfort) add_subdirectory(linklist-lib) +include_directories(${LIBXML2_INCLUDE_DIRS}) + add_executable(${PROJECT_NAME} ${CFILES}) -target_link_libraries(${PROJECT_NAME} ${ELF_LIBRARIES} fort linklist-lib) -target_link_directories(${PROJECT_NAME} PRIVATE ${ELF_LIBRARY_DIRS}) +target_link_libraries(${PROJECT_NAME} ${ELF_LIBRARIES} ${LIBXML2_LIBRARIES} fort linklist-lib) +target_link_directories(${PROJECT_NAME} PRIVATE ${ELF_LIBRARY_DIRS} ${LIBXML2_LIBRARY_DIRS}) target_include_directories(${PROJECT_NAME} PRIVATE ${ELF_INCLUDE_DIRS}) target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include") target_include_directories(${PROJECT_NAME} PRIVATE "include") diff --git a/include/patchelfcrc/elfpatch.h b/include/patchelfcrc/elfpatch.h index c8646db..70cc2eb 100644 --- a/include/patchelfcrc/elfpatch.h +++ b/include/patchelfcrc/elfpatch.h @@ -50,6 +50,19 @@ elfpatch_handle_t *elf_patch_open(const char *path, bool readonly); */ int elf_patch_check_for_section(elfpatch_handle_t *ep, const char *section); +/** + * @brief Get VMA, LMA and size of section + * @param ep Elfpatch handle + * @param[in] section section name + * @param[out] vma Virtual Memory Address. May be NULL. + * @param[out] len Size of section in bytes. May be NULL. + * @return 0 if successful + * @return -1 if section is not found + * @return -1000 and below: Parameter error. + */ +int elf_patch_get_section_address(elfpatch_handle_t *ep, const char *section, + uint64_t *vma, uint64_t *len); + /** * @brief Compute CRC over a section in an ELF file * @param ep Elf patch object diff --git a/include/patchelfcrc/xml.h b/include/patchelfcrc/xml.h new file mode 100644 index 0000000..ecfdfec --- /dev/null +++ b/include/patchelfcrc/xml.h @@ -0,0 +1,14 @@ +#ifndef _ELFPATCHCRC_XML_H_ +#define _ELFPATCHCRC_XML_H_ + +#include +#include +#include +#include + +void xml_init(void); + +int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *section_names, + const struct crc_settings *crc_params, elfpatch_handle_t *ep); + +#endif /* _ELFPATCHCRC_XML_H_ */ diff --git a/src/elfpatch.c b/src/elfpatch.c index b2cb876..10a4696 100644 --- a/src/elfpatch.c +++ b/src/elfpatch.c @@ -482,6 +482,17 @@ static size_t calculate_needed_space_for_crcs(elfpatch_handle_t *ep, return needed_space; } +static void get_section_addr_and_length(const struct elf_section *sec, uint64_t *vma, uint64_t *len) +{ + if (!sec) + return; + + if (vma) + *vma = sec->section_header.sh_addr; + if (len) + *len = sec->section_header.sh_size; +} + int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, const SlList *section_name_list, const uint32_t *crcs, uint8_t crc_size_bits, uint32_t start_magic, uint32_t end_magic, bool check_start_magic, bool check_end_magic, enum crc_format format, bool little_endian) @@ -673,3 +684,21 @@ void elf_patch_close_and_free(elfpatch_handle_t *ep) free(ep); } + +int elf_patch_get_section_address(elfpatch_handle_t *ep, const char *section, + uint64_t *vma, uint64_t *len) +{ + const struct elf_section *sec; + + ret_val_if_ep_err(ep, -1001); + if (!section) + return -1002; + + sec = find_section_in_list(ep->sections, section); + if (!sec) + return -1; + + get_section_addr_and_length(sec, vma, len); + + return 0; +} diff --git a/src/main.c b/src/main.c index a81fb34..b6ad97c 100644 --- a/src/main.c +++ b/src/main.c @@ -27,6 +27,7 @@ #include #include #include +#include #include const char *argp_program_bug_address = ""; @@ -35,6 +36,8 @@ const char *argp_program_bug_address = "has_end_magic = true; args->end_magic = strtoul(arg, NULL, 0); break; + case ARG_KEY_EXPORT: + args->export_xml = arg; + break; + case ARG_KEY_IMPORT: + args->import_xml = arg; + break; case ARG_KEY_LIST: args->list = true; break; @@ -144,7 +155,6 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) return ARGP_ERR_UNKNOWN; } - return 0; } @@ -170,7 +180,9 @@ static int parse_cmdline_options(int *argc, char ***argv, struct command_line_op {"crc-format", 'F', "FORMAT", 0, "Output Format for CRCs.", 2}, {"start-magic", ARG_KEY_START_MAGIC, "STARTMAGIC", 0, "Check output section for start magic (uint32)", 2}, {"end-magic", ARG_KEY_END_MAGIC, "STARTMAGIC", 0, "Check output section for start magic (uint32)", 2}, - {"list-crcs", ARG_KEY_LIST, 0, 0 , "List predefined CRCs", 0}, + {"list-crcs", ARG_KEY_LIST, 0, 0, "List predefined CRCs", 0}, + {"export", ARG_KEY_EXPORT, "XML", 0, "Export CRCs to XML file", 3}, + {"import", ARG_KEY_IMPORT, "XML", 0, "Do not caclulate CRCs but import them from file", 3}, /* Sentinel */ {NULL, 0, 0, 0, NULL, 0} }; @@ -205,6 +217,8 @@ static void prepare_default_opts(struct command_line_options *opts) opts->section_list = NULL; opts->elf_path = NULL; opts->output_section = NULL; + opts->export_xml = NULL; + opts->import_xml = NULL; } static void print_verbose_start_info(const struct command_line_options *cmd_opts) @@ -241,6 +255,14 @@ static void print_verbose_start_info(const struct command_line_options *cmd_opts print_debug("Output section: %s\n", cmd_opts->output_section); } + if (cmd_opts->export_xml) { + print_debug("Export CRCs to '%s'\n", cmd_opts->export_xml); + } + + if (cmd_opts->import_xml) { + print_debug("Import CRCs from '%s'\n", cmd_opts->import_xml); + } + if (cmd_opts->section_list) { for (list_iter = cmd_opts->section_list, i = 1; list_iter; list_iter = sl_list_next(list_iter), i++) { print_debug("Input section [%d]: \"%s\"\n", i, (const char *)list_iter->data); @@ -329,6 +351,7 @@ static int compute_crcs(elfpatch_handle_t *ep, SlList *list, const struct comman crcs[idx] = crc_get_value(crc); } + crc_destroy(crc); return ret; } @@ -366,6 +389,8 @@ int main(int argc, char **argv) int ret = 0; uint32_t *crcs; + xml_init(); + prepare_default_opts(&cmd_opts); parse_cmdline_options(&argc, &argv, &cmd_opts); @@ -384,8 +409,13 @@ int main(int argc, char **argv) return -1; } - if (!cmd_opts.output_section) { - print_err("No output section specified. Will continue but not patch file.\n"); + if (cmd_opts.export_xml && cmd_opts.import_xml) { + print_err("XML export and input cannot be specified at the same time."); + return -2; + } + + if (!cmd_opts.output_section && cmd_opts.export_xml == NULL) { + print_err("No output section / XML export specified. Will continue but not create any output\n"); } /* Do error printing if using a reversed polynomial. It is not implemented yet! */ @@ -420,15 +450,22 @@ int main(int argc, char **argv) if (cmd_opts.output_section) { if (elf_patch_write_crcs_to_section(ep, cmd_opts.output_section, cmd_opts.section_list, - crcs, 32, cmd_opts.start_magic, cmd_opts.end_magic, + crcs, crc_len_from_poly(cmd_opts.crc.polynomial), + cmd_opts.start_magic, cmd_opts.end_magic, cmd_opts.has_start_magic, cmd_opts.has_end_magic, cmd_opts.format, cmd_opts.little_endian)) { ret = -1; } } + if (cmd_opts.export_xml) { + xml_write_crcs_to_file(cmd_opts.export_xml, crcs, cmd_opts.section_list, &cmd_opts.crc, ep); + } + elf_patch_close_and_free(ep); + /* Free the CRCs. This is not strictly necessary... */ + free(crcs); free_cmds: free_cmd_args(&cmd_opts); diff --git a/src/xml.c b/src/xml.c new file mode 100644 index 0000000..fe4869b --- /dev/null +++ b/src/xml.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +void xml_init(void) +{ + LIBXML_TEST_VERSION; +} + +int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *section_name_list, + const struct crc_settings *crc_params, elfpatch_handle_t *ep) +{ + int ret = 0; + xmlTextWriter *writer; + SlList *name_iter; + const char *section_name; + size_t index; + uint64_t vma, len; + + if (!path || !crcs || !section_name_list || !crc_params || !ep) { + return -1000; + } + + writer = xmlNewTextWriterFilename(path, 0); + if (!writer) { + print_err("Cannot create XML file %s\n", path) + ret = -1; + goto ret_none; + } + + xmlTextWriterSetIndentString(writer, BAD_CAST "\t"); + xmlTextWriterSetIndent(writer, 1); + + xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL); + + xmlTextWriterStartElement(writer, BAD_CAST "settings"); + xmlTextWriterWriteFormatElement(writer, BAD_CAST "poly", "0x%" PRIx64, crc_params->polynomial); + xmlTextWriterWriteFormatElement(writer, BAD_CAST "start", "0x%" PRIx32, crc_params->start_value); + xmlTextWriterWriteFormatElement(writer, BAD_CAST "rev", "%s", crc_params->rev ? "true" : "false"); + xmlTextWriterWriteFormatElement(writer, BAD_CAST "xor", "0x%" PRIx32, crc_params->xor); + xmlTextWriterEndElement(writer); /* End settings */ + + xmlTextWriterStartElement(writer, BAD_CAST "sections"); + + /* Output all section CRCs */ + for (name_iter = section_name_list, index = 0u; name_iter; name_iter = sl_list_next(name_iter), index++) { + section_name = (const char *)name_iter->data; + xmlTextWriterStartElement(writer, BAD_CAST "crc"); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "name", "%s", section_name); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "index", "%zu", index); + if (elf_patch_get_section_address(ep, section_name, &vma, &len)) { + print_err("Could not retrieve section address / length of section '%s'. XML output will be faulty.\n", + section_name); + } + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "vma", "0x%" PRIx64, vma); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "size", "0x%" PRIx64, len); + xmlTextWriterWriteFormatRaw(writer, "0x%" PRIx32, crcs[index]); + xmlTextWriterEndElement(writer); /* End crc */ + } + xmlTextWriterEndElement(writer); /* End sections */ + xmlTextWriterEndDocument(writer); + + xmlFreeTextWriter(writer); +ret_none: + return ret; +} From ea81d0a8fd23cfb9a85dd38e670d965853067e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 3 Jan 2023 23:08:29 +0100 Subject: [PATCH 02/18] XML Export / Import Progress: * Exporter finished * Imported started. Currently reading in nodes and printing them. * Add XSD file for automatic validation. Working. TODO: * Correcly handle main logic of import export * Finish importer --- CMakeLists.txt | 12 ++- include/patchelfcrc/elfpatch.h | 8 ++ include/patchelfcrc/xml.h | 26 ++++++ resources/schema.xsd | 38 ++++++++ src/elfpatch.c | 21 +++++ src/main.c | 9 +- src/xml.c | 161 ++++++++++++++++++++++++++++++++- 7 files changed, 269 insertions(+), 6 deletions(-) create mode 100644 resources/schema.xsd diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b65ccb..23a7921 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,8 +40,18 @@ add_custom_target( mkdir -p ${GEN_HEADER_PATH} && bash "${CMAKE_CURRENT_SOURCE_DIR}/gen_version_header.sh" "${GEN_HEADER_PATH}/version.h" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Generating version header" ) +add_custom_target(schema-header DEPENDS "${GEN_HEADER_PATH}/schema-blob.h") +add_custom_command( + OUTPUT "${GEN_HEADER_PATH}/schema-blob.h" + COMMAND mkdir -p ${GEN_HEADER_PATH} && bash -c "xxd -i schema.xsd>${GEN_HEADER_PATH}/schema-blob.h" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/resources/schema.xsd" + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/resources" + COMMENT "Generating XML schema" +) + add_compile_options(-Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter) set(FORT_ENABLE_TESTING OFF CACHE INTERNAL "") @@ -56,7 +66,7 @@ target_link_directories(${PROJECT_NAME} PRIVATE ${ELF_LIBRARY_DIRS} ${LIBXML2_LI target_include_directories(${PROJECT_NAME} PRIVATE ${ELF_INCLUDE_DIRS}) target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include") target_include_directories(${PROJECT_NAME} PRIVATE "include") -add_dependencies(${PROJECT_NAME} version-header) +add_dependencies(${PROJECT_NAME} version-header schema-header) if (DOXYGEN_FOUND) set(DOXYFILE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/doxygen/Doxyfile.in") diff --git a/include/patchelfcrc/elfpatch.h b/include/patchelfcrc/elfpatch.h index 70cc2eb..437996b 100644 --- a/include/patchelfcrc/elfpatch.h +++ b/include/patchelfcrc/elfpatch.h @@ -50,6 +50,14 @@ elfpatch_handle_t *elf_patch_open(const char *path, bool readonly); */ int elf_patch_check_for_section(elfpatch_handle_t *ep, const char *section); +/** + * @brief Get bit size of opened elf file + * @param ep Elfpath handle + * @return positive: Bits of ELF file. Either 32 or 64 + * @return negative, if error + */ +int elf_patch_get_bits(elfpatch_handle_t *ep); + /** * @brief Get VMA, LMA and size of section * @param ep Elfpatch handle diff --git a/include/patchelfcrc/xml.h b/include/patchelfcrc/xml.h index ecfdfec..83f3684 100644 --- a/include/patchelfcrc/xml.h +++ b/include/patchelfcrc/xml.h @@ -6,9 +6,35 @@ #include #include +struct xml_crc_entry { + uint64_t vma; + uint64_t size; + uint32_t crc; +}; + +struct xml_crc_import { + int elf_bits; + struct crc_settings crc_config; + SlList *xml_crc_entries; /**< @brief linked list of @ref xml_crc_entry structs */ +}; + void xml_init(void); int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *section_names, const struct crc_settings *crc_params, elfpatch_handle_t *ep); +/** + * @brief xml_import_from_file Import from file + * @param path Path to import from + * @return Returns a newly allocated struct. Must be freed with @ref xml_crc_import_free + * @return NULL in case of error + */ +struct xml_crc_import *xml_import_from_file(const char *path); + +/** + * @brief Fully free supplied import data + * @param data Data to free + */ +void xml_crc_import_free(struct xml_crc_import *data); + #endif /* _ELFPATCHCRC_XML_H_ */ diff --git a/resources/schema.xsd b/resources/schema.xsd new file mode 100644 index 0000000..fb7d3a1 --- /dev/null +++ b/resources/schema.xsd @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/elfpatch.c b/src/elfpatch.c index 10a4696..0aefbb7 100644 --- a/src/elfpatch.c +++ b/src/elfpatch.c @@ -702,3 +702,24 @@ int elf_patch_get_section_address(elfpatch_handle_t *ep, const char *section, return 0; } + +int elf_patch_get_bits(elfpatch_handle_t *ep) +{ + int bitsize; + + ret_val_if_ep_err(ep, -1001); + + switch (ep->class) { + case ELFCLASS32: + bitsize = 32; + break; + case ELFCLASS64: + bitsize = 64; + break; + default: + bitsize = -1; + break; + } + + return bitsize; +} diff --git a/src/main.c b/src/main.c index b6ad97c..d451402 100644 --- a/src/main.c +++ b/src/main.c @@ -459,9 +459,14 @@ int main(int argc, char **argv) } if (cmd_opts.export_xml) { - xml_write_crcs_to_file(cmd_opts.export_xml, crcs, cmd_opts.section_list, &cmd_opts.crc, ep); - } + if (xml_write_crcs_to_file(cmd_opts.export_xml, crcs, cmd_opts.section_list, &cmd_opts.crc, ep)) { + print_err("Error during XML generation\n"); + ret = -3; + } + /* Fix this: */ + (void)xml_import_from_file(cmd_opts.export_xml); + } elf_patch_close_and_free(ep); /* Free the CRCs. This is not strictly necessary... */ diff --git a/src/xml.c b/src/xml.c index fe4869b..56c8ff2 100644 --- a/src/xml.c +++ b/src/xml.c @@ -4,11 +4,14 @@ #include #include #include +#include #include #include #include #include +#include +#include void xml_init(void) { @@ -19,6 +22,7 @@ int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *secti const struct crc_settings *crc_params, elfpatch_handle_t *ep) { int ret = 0; + int bitsize; xmlTextWriter *writer; SlList *name_iter; const char *section_name; @@ -32,20 +36,29 @@ int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *secti writer = xmlNewTextWriterFilename(path, 0); if (!writer) { print_err("Cannot create XML file %s\n", path) - ret = -1; + ret = -1; goto ret_none; } - xmlTextWriterSetIndentString(writer, BAD_CAST "\t"); - xmlTextWriterSetIndent(writer, 1); + //xmlTextWriterSetIndentString(writer, BAD_CAST "\t"); + //xmlTextWriterSetIndent(writer, 1); xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL); + /* Generate the root node */ + xmlTextWriterStartElement(writer, BAD_CAST "patchelfcrc"); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "version", "%s", version_string); xmlTextWriterStartElement(writer, BAD_CAST "settings"); xmlTextWriterWriteFormatElement(writer, BAD_CAST "poly", "0x%" PRIx64, crc_params->polynomial); xmlTextWriterWriteFormatElement(writer, BAD_CAST "start", "0x%" PRIx32, crc_params->start_value); xmlTextWriterWriteFormatElement(writer, BAD_CAST "rev", "%s", crc_params->rev ? "true" : "false"); xmlTextWriterWriteFormatElement(writer, BAD_CAST "xor", "0x%" PRIx32, crc_params->xor); + bitsize = elf_patch_get_bits(ep); + if (bitsize < 0) { + print_err("Cannot determine ELF class. Generated XML will be faulty.\n"); + ret |= -1; + } + xmlTextWriterWriteFormatElement(writer, BAD_CAST "elfclass", "%d", bitsize); xmlTextWriterEndElement(writer); /* End settings */ xmlTextWriterStartElement(writer, BAD_CAST "sections"); @@ -59,6 +72,7 @@ int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *secti if (elf_patch_get_section_address(ep, section_name, &vma, &len)) { print_err("Could not retrieve section address / length of section '%s'. XML output will be faulty.\n", section_name); + ret |= -1; } xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "vma", "0x%" PRIx64, vma); xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "size", "0x%" PRIx64, len); @@ -66,9 +80,150 @@ int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *secti xmlTextWriterEndElement(writer); /* End crc */ } xmlTextWriterEndElement(writer); /* End sections */ + + xmlTextWriterEndElement(writer); /* End root node */ + xmlTextWriterEndDocument(writer); xmlFreeTextWriter(writer); ret_none: return ret; } + +static struct xml_crc_import *xml_crc_import_alloc(void) +{ + struct xml_crc_import *ret = NULL; + + ret = (struct xml_crc_import *)malloc(sizeof(struct xml_crc_import)); + if (ret) + ret->xml_crc_entries = NULL; + else + print_err("Error. Out of memory. This should never happen\n"); + + return ret; +} + +static void recusive_node_iter(xmlNodePtr node, int level) +{ + int i; + xmlNodePtr iter; + xmlAttrPtr attr; + xmlChar *t; + + for (i = level; i > 0; i--) + printf(" "); + + if (node->content) + printf("Node <%s> (%d) >%s<", node->name, node->type, node->content); + else + printf("Node <%s> (%d)", node->name, node->type); + if (node->properties) { + for (attr = node->properties; attr; attr = attr->next) { + t = xmlNodeListGetString(node->doc, attr->children, 1); + printf(" %s=\"%s\"", attr->name, t); + xmlFree(t); + } + } + printf("\n"); + for (iter = node->children; iter; iter = iter->next) { + recusive_node_iter(iter, level + 1); + } +} + +static bool validate_xml_doc(xmlDocPtr doc) +{ + bool ret = false; + xmlSchemaParserCtxtPtr parser_ctx = NULL; + xmlSchemaPtr schema = NULL; + xmlSchemaValidCtxtPtr validation_ctx = NULL; + int res; + + parser_ctx = xmlSchemaNewMemParserCtxt((const char *)schema_xsd, schema_xsd_len); + if (!parser_ctx) { + print_err("Cannot create parse context for built-in XSD. This is a bug. Report this.\n"); + goto ret_none; + } + + schema = xmlSchemaParse(parser_ctx); + if (!schema) { + print_err("Cannot parse built-in XSD. This is a bug. Report this.\n"); + goto ret_none; + } + + validation_ctx = xmlSchemaNewValidCtxt(schema); + if (!validation_ctx) { + print_err("Cannot create validation context. This is a bug. Report this.\n"); + goto ret_none; + } + + res = xmlSchemaValidateDoc(validation_ctx, doc); + ret = (res == 0 ? true : false); + +ret_none: + /* Clean up */ + if (validation_ctx) + xmlSchemaFreeValidCtxt(validation_ctx); + if (schema) + xmlSchemaFree(schema); + if (parser_ctx) + xmlSchemaFreeParserCtxt(parser_ctx); + return ret; +} + +struct xml_crc_import *xml_import_from_file(const char *path) +{ + struct xml_crc_import *ret = NULL; + xmlDocPtr doc; + xmlNodePtr root_node, settings_node, crc_node, iter; + + if (!path) + return NULL; + + doc = xmlReadFile(path, NULL, 0); + if (!doc) { + print_err("Error reading XML file: %s\n", path); + goto ret_none; + } + root_node = xmlDocGetRootElement(doc); + if (!root_node) { + goto ret_close_doc; + } + + /* Validate the document */ + if (!validate_xml_doc(doc)) { + print_err("XML does not match expected format. Cannot import.\n"); + goto ret_close_doc; + } + + /* Allocate xml import structure */ + ret = xml_crc_import_alloc(); + if (!ret) + goto ret_close_doc; + + recusive_node_iter(root_node, 0); + + +ret_close_doc: + /* Free document and all of its children */ + xmlFreeDoc(doc); + + /* Cleanup global garbage */ + xmlCleanupParser(); +ret_none: + return ret; +} + +static void free_xml_crc_entry(void *entry) { + if (entry) + free(entry); +} + +void xml_crc_import_free(struct xml_crc_import *data) +{ + if (!data) + return; + + sl_list_free_full(data->xml_crc_entries, free_xml_crc_entry); + data->xml_crc_entries = NULL; + free(data); +} From 3bd46d888d33e180120799e65ea5a0f1a08a267d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 4 Jan 2023 14:35:34 +0100 Subject: [PATCH 03/18] Improve XSD and XML format --- resources/schema.xsd | 50 ++++++++++++++++++++++++++++++++++---------- src/xml.c | 9 +++++--- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/resources/schema.xsd b/resources/schema.xsd index fb7d3a1..215affd 100644 --- a/resources/schema.xsd +++ b/resources/schema.xsd @@ -1,34 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - + - + - - - + + + - + diff --git a/src/xml.c b/src/xml.c index 56c8ff2..fe08e6d 100644 --- a/src/xml.c +++ b/src/xml.c @@ -40,8 +40,8 @@ int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *secti goto ret_none; } - //xmlTextWriterSetIndentString(writer, BAD_CAST "\t"); - //xmlTextWriterSetIndent(writer, 1); + xmlTextWriterSetIndentString(writer, BAD_CAST "\t"); + xmlTextWriterSetIndent(writer, 1); xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL); /* Generate the root node */ @@ -51,7 +51,10 @@ int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *secti xmlTextWriterStartElement(writer, BAD_CAST "settings"); xmlTextWriterWriteFormatElement(writer, BAD_CAST "poly", "0x%" PRIx64, crc_params->polynomial); xmlTextWriterWriteFormatElement(writer, BAD_CAST "start", "0x%" PRIx32, crc_params->start_value); - xmlTextWriterWriteFormatElement(writer, BAD_CAST "rev", "%s", crc_params->rev ? "true" : "false"); + if (crc_params->rev) { + xmlTextWriterStartElement(writer, BAD_CAST "rev"); + xmlTextWriterEndElement(writer); + } xmlTextWriterWriteFormatElement(writer, BAD_CAST "xor", "0x%" PRIx32, crc_params->xor); bitsize = elf_patch_get_bits(ep); if (bitsize < 0) { From b3827b25c6f694fafc94511f37b431cd920bfabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 4 Jan 2023 14:47:19 +0100 Subject: [PATCH 04/18] Add --xsd option to print out the used XSD --- include/patchelfcrc/xml.h | 5 +++++ man/patchelfcrc.1.md | 10 ++++++++-- resources/schema.xsd | 1 + src/main.c | 11 +++++++++++ src/xml.c | 5 +++++ 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/include/patchelfcrc/xml.h b/include/patchelfcrc/xml.h index 83f3684..6cd4e24 100644 --- a/include/patchelfcrc/xml.h +++ b/include/patchelfcrc/xml.h @@ -37,4 +37,9 @@ struct xml_crc_import *xml_import_from_file(const char *path); */ void xml_crc_import_free(struct xml_crc_import *data); +/** + * @brief Print XML XSD file to stdout + */ +void xml_print_xsd(void); + #endif /* _ELFPATCHCRC_XML_H_ */ diff --git a/man/patchelfcrc.1.md b/man/patchelfcrc.1.md index 62370bf..63cdf7a 100644 --- a/man/patchelfcrc.1.md +++ b/man/patchelfcrc.1.md @@ -8,7 +8,7 @@ # SYNOPSYS **patchelfcrc** [**-lrv?V**] [**-g** *GRANULARITY*] [**-p** *POLYNOMIAL*] [**-s** *STARTVALUE*] [**-x** *XORVAL*] [**-F** *FORMAT*] [**-O** *OUTPUTSECTION*] [**-S** *SEC*] -[**\--granularity**=*GRANULARITY*] [**\--little-endian**] [**\--dry-run**] +[**\--granularity**=*GRANULARITY*] [**\--little-endian**] [**\--dry-run**] [**\--xsd**] [**\--poly**=*POLYNOMIAL*] [**\--reversed**] [**\--start-value**=*STARTVALUE*] [**--verbose**] [**\--xor-out**=*XORVAL*] [**\--end-magic**=*MAGIC*] [**\--crc-format**=*FORMAT*] [**\--list-crcs**] [**\--output-section**=*OUTPUTSECTION*] @@ -65,6 +65,12 @@ **-V**, **\--version** : Print version number +**\--list-crcs** +: List the possible predefined CRCs + +**\--xsd** +: Print the XSD file used to validate the XML import to stdout + **--usage** : Print usage hints on command line options. @@ -120,4 +126,4 @@ The output sections start and end are checked for the given magic numbers in ord The memory is interpreted as *little endian* and the CRC calculation granularity is a 32 bit *word*. # BUGS -Currently, reversed CRC algorithms are not implemented. \ No newline at end of file +Currently, reversed CRC algorithms are not implemented. diff --git a/resources/schema.xsd b/resources/schema.xsd index 215affd..874ddbb 100644 --- a/resources/schema.xsd +++ b/resources/schema.xsd @@ -64,3 +64,4 @@ + diff --git a/src/main.c b/src/main.c index d451402..ceb59c4 100644 --- a/src/main.c +++ b/src/main.c @@ -38,11 +38,13 @@ const char *argp_program_bug_address = "list = true; break; + case ARG_KEY_XSD: + args->print_xsd = true; + break; case 'p': /* Polyniomial */ args->crc.polynomial = strtoull(arg, &endptr, 0); @@ -183,6 +188,7 @@ static int parse_cmdline_options(int *argc, char ***argv, struct command_line_op {"list-crcs", ARG_KEY_LIST, 0, 0, "List predefined CRCs", 0}, {"export", ARG_KEY_EXPORT, "XML", 0, "Export CRCs to XML file", 3}, {"import", ARG_KEY_IMPORT, "XML", 0, "Do not caclulate CRCs but import them from file", 3}, + {"xsd", ARG_KEY_XSD, 0, 0, "Print XSD to stdout", 0}, /* Sentinel */ {NULL, 0, 0, 0, NULL, 0} }; @@ -204,6 +210,7 @@ static void prepare_default_opts(struct command_line_options *opts) { opts->little_endian = false; opts->verbose = false; + opts->print_xsd = false; opts->granularity = GRANULARITY_BYTE; opts->dry_run = false; opts->crc.xor = 0UL; @@ -393,6 +400,10 @@ int main(int argc, char **argv) prepare_default_opts(&cmd_opts); parse_cmdline_options(&argc, &argv, &cmd_opts); + if (cmd_opts.print_xsd) { + xml_print_xsd(); + goto free_cmds; + } if (cmd_opts.verbose || cmd_opts.dry_run) reporting_enable_verbose(); diff --git a/src/xml.c b/src/xml.c index fe08e6d..683d39c 100644 --- a/src/xml.c +++ b/src/xml.c @@ -230,3 +230,8 @@ void xml_crc_import_free(struct xml_crc_import *data) data->xml_crc_entries = NULL; free(data); } + +void xml_print_xsd(void) +{ + printf("%.*s", schema_xsd_len, schema_xsd); +} From 5d86a261d42c596ac547c01c7dcaa580390d81ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 4 Jan 2023 15:56:49 +0100 Subject: [PATCH 05/18] Add dependencies to PKGBUILD --- AUR/PKGBUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AUR/PKGBUILD b/AUR/PKGBUILD index 1fcd25f..459792f 100644 --- a/AUR/PKGBUILD +++ b/AUR/PKGBUILD @@ -7,8 +7,8 @@ pkgdesc="Tool for patching CRC checksums of sections into ELF binaries" arch=('i686' 'x86_64') url="https://git.shimatta.de/mhu/patchelfcrc" licence=('GPLv2') -depends=('libelf') -makedepends=('cmake' 'pandoc' 'git') +depends=('libelf' 'libxml2') +makedepends=('cmake' 'pandoc' 'git' 'gvim') provides=('patchelfcrc') source=("${pkgname}-git"::"git+https://git.shimatta.de/mhu/patchelfcrc" "git+https://git.shimatta.de/3rd-party/libfort.git" "git+https://git.shimatta.de/mhu/linklist-lib") sha1sums=('SKIP' 'SKIP' 'SKIP') From fda6e926151e645c783bea8f0d578d79de2563cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 4 Jan 2023 19:54:27 +0100 Subject: [PATCH 06/18] Successfully import CRC config data --- src/main.c | 5 +- src/xml.c | 198 +++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 174 insertions(+), 29 deletions(-) diff --git a/src/main.c b/src/main.c index 8a5cb07..c50a441 100644 --- a/src/main.c +++ b/src/main.c @@ -395,6 +395,7 @@ int main(int argc, char **argv) elfpatch_handle_t *ep; int ret = 0; uint32_t *crcs = NULL; + struct xml_crc_import *import_data = NULL; xml_init(); @@ -477,7 +478,7 @@ int main(int argc, char **argv) ret = -3; } /* Fix this: */ - (void)xml_import_from_file(cmd_opts.export_xml); + import_data = xml_import_from_file(cmd_opts.export_xml); } @@ -490,6 +491,8 @@ free_cmds: /* Free CRCs if necessary */ if (crcs) free(crcs); + if (import_data) + xml_crc_import_free(import_data); return ret; } diff --git a/src/xml.c b/src/xml.c index 683d39c..106fca9 100644 --- a/src/xml.c +++ b/src/xml.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -7,6 +8,8 @@ #include #include +#include +#include #include #include #include @@ -106,33 +109,6 @@ static struct xml_crc_import *xml_crc_import_alloc(void) return ret; } -static void recusive_node_iter(xmlNodePtr node, int level) -{ - int i; - xmlNodePtr iter; - xmlAttrPtr attr; - xmlChar *t; - - for (i = level; i > 0; i--) - printf(" "); - - if (node->content) - printf("Node <%s> (%d) >%s<", node->name, node->type, node->content); - else - printf("Node <%s> (%d)", node->name, node->type); - if (node->properties) { - for (attr = node->properties; attr; attr = attr->next) { - t = xmlNodeListGetString(node->doc, attr->children, 1); - printf(" %s=\"%s\"", attr->name, t); - xmlFree(t); - } - } - printf("\n"); - for (iter = node->children; iter; iter = iter->next) { - recusive_node_iter(iter, level + 1); - } -} - static bool validate_xml_doc(xmlDocPtr doc) { bool ret = false; @@ -173,11 +149,143 @@ ret_none: return ret; } +/** + * @brief Get the content of a node specified by the xpath \p path + * @param path Xpath to search for + * @param xpath_ctx Context + * @param required Print error if not found + * @return NULL in case of error + * @return pointer to newly alloceted string data. + * @note Pointers retured from this function must be freed using xmlFree() + */ +static const char *get_node_content_from_xpath(const char *path, xmlXPathContextPtr xpath_ctx, bool required) +{ + xmlXPathObjectPtr xpath_obj; + const char *ret = NULL; + + xpath_obj = xmlXPathEvalExpression(BAD_CAST path, xpath_ctx); + if (xpath_obj) { + if (xmlXPathNodeSetIsEmpty(xpath_obj->nodesetval)) { + if (required) + print_err("Required XML path %s not found.\n", path); + + } else { + ret = (const char *)xmlNodeGetContent(xpath_obj->nodesetval->nodeTab[0]); + } + xmlXPathFreeObject(xpath_obj); + } else { + /* Error */ + print_err("Error searching for path %s in XML. This is an error. Report this.\n", path); + } + + return ret; +} + + +/** + * @brief Convert a number string (either prefixed 0x hex or decimal) to a uint64 + * + * In case of an error, the \p output remains untouched + * + * @param[in] data input data. 0 terminated + * @param[in] output Converted number. + * @return 0 if okay + * @return negative in case of error + */ +static int convert_number_string_to_uint(const char *data, uint64_t *output) +{ + int ret = -1; + uint64_t num; + char *endptr; + + if (!data || !output) + return -1000; + + errno = 0; + num = strtoull(data, &endptr, 0); + if (endptr == data) { + /* Error finding number */ + print_err("Data %s in XML is not a valid number\n", data); + } else if (errno == ERANGE) { + print_err("Data %s in XML overflowed\n", data); + } else if (errno == EINVAL) { + print_err("Unspecified error converting '%s' to a number\n", data); + } else if (errno == 0 && data && *endptr != '\0') { + print_err("Data '%s' could not be fully parsed to a number. Part '%s' is irritating\n", data, endptr); + } else if (errno == 0 && data && *endptr == '\0') { + ret = 0; + *output = num; + } + + return ret; +} + +/** + * @brief Get the content of an xpath and convert it to a uint64_t + * @param[in] xpath Path to get content from + * @param[in] xpath_ctx Xpath context + * @param[out] output Number output. Remains untouched in case of an error + * @param required This xpath is required. Will turn on error reporting if it is not found. + * @return 0 if successful + * @return negative in case of an error + */ +static int get_uint64_from_xpath_content(const char *xpath, xmlXPathContextPtr xpath_ctx, uint64_t *output, bool required) +{ + const char *data; + int ret = -1; + + data = get_node_content_from_xpath(xpath, xpath_ctx, required); + if (data) { + ret = convert_number_string_to_uint(data, output); + xmlFree((void *)data); + } + + return ret; +} + +/** + * @brief Get the content of an xpath and convert it to a uint64_t + * @param[in] xpath Path to get content from + * @param[in] xpath_ctx Xpath context + * @param[out] output Number output. Remains untouched in case of an error + * @param required This xpath is required. Will turn on error reporting if it is not found. + * @return 0 if successful + * @return negative in case of an error + */ +static int get_uint32_from_xpath_content(const char *xpath, xmlXPathContextPtr xpath_ctx, uint32_t *output, bool required) +{ + const char *data; + uint64_t tmp; + int ret = -1; + + data = get_node_content_from_xpath(xpath, xpath_ctx, required); + if (data) { + ret = convert_number_string_to_uint(data, &tmp); + xmlFree((void *)data); + + if (ret == 0) { + if (tmp > UINT32_MAX) { + ret = -2; + print_err("Value in XML file at path '%s' is too large for uint32_t\n", xpath); + } else { + *output = (uint32_t)tmp; + } + } + } + + return ret; +} + + struct xml_crc_import *xml_import_from_file(const char *path) { struct xml_crc_import *ret = NULL; xmlDocPtr doc; xmlNodePtr root_node, settings_node, crc_node, iter; + xmlXPathContextPtr xpath_ctx = NULL; + uint64_t tmp_num64 = 0; + uint32_t tmp_num32 = 0; + const char *cptr; if (!path) return NULL; @@ -198,15 +306,47 @@ struct xml_crc_import *xml_import_from_file(const char *path) goto ret_close_doc; } + /* Get xpath context */ + xpath_ctx = xmlXPathNewContext(doc); + if (!xpath_ctx) { + goto ret_close_doc; + } + /* Allocate xml import structure */ ret = xml_crc_import_alloc(); if (!ret) goto ret_close_doc; - recusive_node_iter(root_node, 0); + /* Do not do extensive error handling. It is assured by the schema that the numbers are parsable */ + (void)get_uint64_from_xpath_content("/patchelfcrc/settings/poly", xpath_ctx, &tmp_num64, true); + ret->crc_config.polynomial = tmp_num64; + + (void)get_uint32_from_xpath_content("/patchelfcrc/settings/start", xpath_ctx, &tmp_num32, true); + ret->crc_config.start_value = tmp_num32; + + (void)get_uint32_from_xpath_content("/patchelfcrc/settings/xor", xpath_ctx, &tmp_num32, true); + ret->crc_config.xor = tmp_num32; + + cptr = get_node_content_from_xpath("/patchelfcrc/settings/rev", xpath_ctx, false); + if (cptr) { + xmlFree((void *)cptr); + ret->crc_config.rev = true; + } else { + ret->crc_config.rev = false; + } + + + goto ret_close_doc; + +ret_dealloc: + xml_crc_import_free(ret); + ret = NULL; ret_close_doc: + if (xpath_ctx) + xmlXPathFreeContext(xpath_ctx); + /* Free document and all of its children */ xmlFreeDoc(doc); @@ -214,6 +354,8 @@ ret_close_doc: xmlCleanupParser(); ret_none: return ret; + + } static void free_xml_crc_entry(void *entry) { From 2c509645814fe4c52376e92e2985fdb411cd2380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 4 Jan 2023 21:42:12 +0100 Subject: [PATCH 07/18] Add preliminary code to read CRCs from XML. CRC value still missing --- src/xml.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 7 deletions(-) diff --git a/src/xml.c b/src/xml.c index 106fca9..3896a34 100644 --- a/src/xml.c +++ b/src/xml.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -155,8 +156,8 @@ ret_none: * @param xpath_ctx Context * @param required Print error if not found * @return NULL in case of error - * @return pointer to newly alloceted string data. - * @note Pointers retured from this function must be freed using xmlFree() + * @return pointer to newly allocated string data. + * @note Pointers returned from this function must be freed using xmlFree() */ static const char *get_node_content_from_xpath(const char *path, xmlXPathContextPtr xpath_ctx, bool required) { @@ -276,15 +277,53 @@ static int get_uint32_from_xpath_content(const char *xpath, xmlXPathContextPtr x return ret; } +int get_uint64_from_node_attribute(xmlNodePtr node, const char *attr, uint64_t *output) +{ + xmlChar *data; + uint64_t num; + int ret = -1; + + data = xmlGetProp(node, BAD_CAST attr); + if (data) { + if (!convert_number_string_to_uint((const char *)data, &num)) { + ret = 0; + *output = num; + } + xmlFree(data); + } + + return ret; +} + +int get_uint32_from_node_attribute(xmlNodePtr node, const char *attr, uint32_t *output) +{ + int ret; + uint64_t tmp = 0; + + ret = get_uint64_from_node_attribute(node, attr, &tmp); + + if (tmp > UINT32_MAX || ret) { + print_err("Cannot conver attribute %s to number\n", attr); + ret = -1; + } else { + *output = (uint32_t)tmp; + } + + return ret; +} struct xml_crc_import *xml_import_from_file(const char *path) { struct xml_crc_import *ret = NULL; + struct xml_crc_entry *crc; xmlDocPtr doc; - xmlNodePtr root_node, settings_node, crc_node, iter; + xmlNodePtr root_node; + xmlNodePtr current_node; xmlXPathContextPtr xpath_ctx = NULL; + xmlXPathObjectPtr xpath_obj = NULL; uint64_t tmp_num64 = 0; uint32_t tmp_num32 = 0; + int i; const char *cptr; if (!path) @@ -312,6 +351,17 @@ struct xml_crc_import *xml_import_from_file(const char *path) goto ret_close_doc; } + /* Get the version number and print error in case of incompatibility. Continue either way */ + cptr = (char *)xmlGetProp(root_node, BAD_CAST "version"); + if (cptr) { + if (strncmp(cptr, version_string, strlen(version_string)) != 0) { + print_err("XML file was generated with another version of patchelfcrc.\n"); + print_err("\t XML shows: %s\n", cptr); + print_err("\t Program version: %s\n", version_string); + } + xmlFree((char *)cptr); + } + /* Allocate xml import structure */ ret = xml_crc_import_alloc(); if (!ret) @@ -336,14 +386,35 @@ struct xml_crc_import *xml_import_from_file(const char *path) ret->crc_config.rev = false; } + (void)get_uint32_from_xpath_content("/patchelfcrc/settings/elfclass", xpath_ctx, &tmp_num32, true); + ret->elf_bits = (int)tmp_num32; - goto ret_close_doc; + /* Get all CRCs */ + xpath_obj = xmlXPathEvalExpression(BAD_CAST "/patchelfcrc/sections/crc", xpath_ctx); + if (xmlXPathNodeSetIsEmpty(xpath_obj->nodesetval)) { + print_err("Internal error during read\n") + xml_crc_import_free(ret); + ret = NULL; + goto ret_close_doc; + } + + for (i = 0; i < xpath_obj->nodesetval->nodeNr; i++) { + current_node = xpath_obj->nodesetval->nodeTab[i]; + crc = (struct xml_crc_entry *)malloc(sizeof(struct xml_crc_entry)); + ret->xml_crc_entries = sl_list_append(ret->xml_crc_entries, crc); + + get_uint64_from_node_attribute(current_node, "vma", &tmp_num64); + printf("vma: %x\n", (uint32_t)tmp_num64); + get_uint64_from_node_attribute(current_node, "size", &tmp_num64); + printf("size: %x\n", (uint32_t)tmp_num64); + + } -ret_dealloc: - xml_crc_import_free(ret); - ret = NULL; ret_close_doc: + + if (xpath_obj) + xmlXPathFreeObject(xpath_obj); if (xpath_ctx) xmlXPathFreeContext(xpath_ctx); From eeb202788493a055724194523982b128ecaa1474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 6 Jan 2023 14:55:31 +0100 Subject: [PATCH 08/18] reimplement reading of program headers. They are needed to derive the LMA of sections --- src/elfpatch.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/elfpatch.c b/src/elfpatch.c index 78fee02..1ab0e1d 100644 --- a/src/elfpatch.c +++ b/src/elfpatch.c @@ -45,6 +45,8 @@ struct elfpatch { GElf_Ehdr ehdr; int class; SlList *sections; + GElf_Phdr *program_headers; /**< @brief Program headers */ + size_t program_headers_count; /**< @brief Number of program headers in the program headers array */ }; #define ELFPATCH_MAGIC 0x8545637Aul @@ -228,6 +230,60 @@ ret_free_section_list: return ret; } +/** + * @brief Read program headers from ELF file and store them more conviniently in a linkled list + * @param ep Elfpatch object + * @return 0 if successful + * @return negative if error. + * @note The function will succeed even if no program heder is found in the file. + */ +static int elf_patch_read_program_headers(elfpatch_handle_t *ep) +{ + size_t header_count = 0ull; + GElf_Phdr *hdr; + size_t i; + + ret_val_if_ep_err(ep, -1001); + + if (ep->program_headers_count > 0 && ep->program_headers) { + /* Free the program headers. They are owned by the ELF object. So no need to free them */ + free(ep->program_headers); + ep->program_headers_count = 0; + } + + if (elf_getphdrnum(ep->elf, &header_count)) { + print_err("Error reading program headers: %s\n", elf_errmsg(-1)); + return -1; + } + + ep->program_headers = (GElf_Phdr *)malloc(header_count * sizeof(GElf_Phdr)); + if (!ep->program_headers) { + /* Mem error. Abort. Program will crash eventually */ + return -1; + } + + for (i = 0u; i < header_count; i++) { + hdr = &ep->program_headers[i]; + if (gelf_getphdr(ep->elf, (int)i, hdr) != hdr) { + print_err("Error reading program header (%zu): %s\n", i, elf_errmsg(-1)); + goto ret_free_err; + } + print_debug("Program Header (i): mem_size: %zu, file_size: %zu, vma: %p, lma: %p, file offset: %zu\n", + (size_t)hdr->p_memsz, (size_t)hdr->p_filesz, (void *)hdr->p_vaddr, (void *)hdr->p_paddr, + hdr->p_offset); + } + + ep->program_headers_count = header_count; + + return 0; + +ret_free_err: + if (ep->program_headers) + free(ep->program_headers); + ep->program_headers_count = 0u; + return -1; +} + static int elf_patch_update_info(elfpatch_handle_t *ep) { Elf_Kind ek; @@ -273,6 +329,11 @@ static int elf_patch_update_info(elfpatch_handle_t *ep) return -1; } + if (elf_patch_read_program_headers(ep)) { + print_err("Error reading program headers.\n"); + return -1; + } + return 0; } @@ -293,6 +354,11 @@ elfpatch_handle_t *elf_patch_open(const char *path, bool readonly, bool expect_l ep->magic = ELFPATCH_MAGIC; ep->readonly = readonly; + /* This shouldn't really be necessary due to the use of calloc() */ + ep->sections = NULL; + ep->program_headers = NULL; + ep->program_headers_count = 0u; + ep->fd = open(path, readonly ? O_RDONLY : O_RDWR, 0); if (ep->fd < 0) { print_err("Error opening file: %s\n", path); @@ -697,6 +763,12 @@ void elf_patch_close_and_free(elfpatch_handle_t *ep) sl_list_free_full(ep->sections, (void (*)(void *))free_elf_section_element); ep->sections = NULL; + if (ep->program_headers) { + free(ep->program_headers); + ep->program_headers = NULL; + } + ep->program_headers_count = 0u; + ep->elf = NULL; ep->fd = 0; From 0df385e4e7ac319240a57b5ec7a06714336eebfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 6 Jan 2023 15:12:45 +0100 Subject: [PATCH 09/18] Add LMA to handling of XML and debug output. LMA notr yet correclty calculated and is always equal to VMA --- include/patchelfcrc/elfpatch.h | 3 ++- resources/schema.xsd | 1 + src/elfpatch.c | 41 +++++++++++++++++++++++++++++----- src/xml.c | 7 +++--- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/include/patchelfcrc/elfpatch.h b/include/patchelfcrc/elfpatch.h index 5d525ed..4d5b778 100644 --- a/include/patchelfcrc/elfpatch.h +++ b/include/patchelfcrc/elfpatch.h @@ -63,13 +63,14 @@ int elf_patch_get_bits(elfpatch_handle_t *ep); * @param ep Elfpatch handle * @param[in] section section name * @param[out] vma Virtual Memory Address. May be NULL. + * @param[out] lma Load memory address. May be NULL. * @param[out] len Size of section in bytes. May be NULL. * @return 0 if successful * @return -1 if section is not found * @return -1000 and below: Parameter error. */ int elf_patch_get_section_address(elfpatch_handle_t *ep, const char *section, - uint64_t *vma, uint64_t *len); + uint64_t *vma, uint64_t *lma, uint64_t *len); /** * @brief Compute CRC over a section in an ELF file diff --git a/resources/schema.xsd b/resources/schema.xsd index 874ddbb..89c2d3f 100644 --- a/resources/schema.xsd +++ b/resources/schema.xsd @@ -51,6 +51,7 @@ + diff --git a/src/elfpatch.c b/src/elfpatch.c index 1ab0e1d..100f60f 100644 --- a/src/elfpatch.c +++ b/src/elfpatch.c @@ -35,6 +35,7 @@ struct elf_section { GElf_Shdr section_header; Elf_Scn *scn; char *name; + uint64_t lma; /**< @Resolved load memory address of a section. May be equivalent to VMA */ }; struct elfpatch { @@ -161,17 +162,18 @@ static void print_sections(elfpatch_handle_t *ep) /* Write header */ ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER); - ft_write_ln(table, "Section", "Type", "Size", "Address", "File Offset"); + ft_write_ln(table, "Section", "Type", "Size", "VMA", "LMA", "File Offset"); for (iter = ep->sections; iter; iter = sl_list_next(iter)) { section = (const struct elf_section *)iter->data; if (!section) continue; - ft_printf_ln(table, "%s|%s|%lu|0x%p|0x%p", + ft_printf_ln(table, "%s|%s|%lu|%p|%p|%p", section->name, section_type_to_str(section->section_header.sh_type), section->section_header.sh_size, (void *)section->section_header.sh_addr, + (void *)section->lma, (void *)section->section_header.sh_offset ); } @@ -211,6 +213,10 @@ static SlList *elf_patch_get_sections(elfpatch_handle_t *ep) free(sec); continue; } + + /* Default setting of LMA if not modified by segment */ + sec->lma = (uint64_t)sec->section_header.sh_addr; + name = elf_strptr(ep->elf, shstrndx, sec->section_header.sh_name); if (name) { sec->name = strdup(name); @@ -220,8 +226,6 @@ static SlList *elf_patch_get_sections(elfpatch_handle_t *ep) ep->sections = ret; - print_sections(ep); - return ret; ret_free_section_list: @@ -284,6 +288,17 @@ ret_free_err: return -1; } +static void resolve_section_lmas(elfpatch_handle_t *ep) +{ + SlList *sec_iter; + + ret_if_ep_err(ep); + + for (sec_iter = ep->sections; sec_iter; sec_iter = sl_list_next(sec_iter)) { + + } +} + static int elf_patch_update_info(elfpatch_handle_t *ep) { Elf_Kind ek; @@ -334,6 +349,12 @@ static int elf_patch_update_info(elfpatch_handle_t *ep) return -1; } + /* Resolve section to segment mapping to calculate the LMA of eachs section */ + resolve_section_lmas(ep); + + /* Print the debug section table */ + print_sections(ep); + return 0; } @@ -572,6 +593,15 @@ static void get_section_addr_and_length(const struct elf_section *sec, uint64_t *len = sec->section_header.sh_size; } +static void get_section_load_addr(const struct elf_section *sec, uint64_t *lma) +{ + if (!sec || !lma) + return; + + *lma = sec->lma; +} + + int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, const SlList *section_name_list, const uint32_t *crcs, uint8_t crc_size_bits, uint32_t start_magic, uint32_t end_magic, bool check_start_magic, bool check_end_magic, enum crc_format format, bool little_endian) @@ -776,7 +806,7 @@ void elf_patch_close_and_free(elfpatch_handle_t *ep) } int elf_patch_get_section_address(elfpatch_handle_t *ep, const char *section, - uint64_t *vma, uint64_t *len) + uint64_t *vma, uint64_t *lma, uint64_t *len) { const struct elf_section *sec; @@ -789,6 +819,7 @@ int elf_patch_get_section_address(elfpatch_handle_t *ep, const char *section, return -1; get_section_addr_and_length(sec, vma, len); + get_section_load_addr(sec, lma); return 0; } diff --git a/src/xml.c b/src/xml.c index 3896a34..4ed7af6 100644 --- a/src/xml.c +++ b/src/xml.c @@ -31,7 +31,7 @@ int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *secti SlList *name_iter; const char *section_name; size_t index; - uint64_t vma, len; + uint64_t vma, len, lma; if (!path || !crcs || !section_name_list || !crc_params || !ep) { return -1000; @@ -76,12 +76,13 @@ int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *secti xmlTextWriterStartElement(writer, BAD_CAST "crc"); xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "name", "%s", section_name); xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "index", "%zu", index); - if (elf_patch_get_section_address(ep, section_name, &vma, &len)) { - print_err("Could not retrieve section address / length of section '%s'. XML output will be faulty.\n", + if (elf_patch_get_section_address(ep, section_name, &vma, &lma, &len)) { + print_err("Could not retrieve section addresses / length of section '%s'. XML output will be faulty.\n", section_name); ret |= -1; } xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "vma", "0x%" PRIx64, vma); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "lma", "0x%" PRIx64, lma); xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "size", "0x%" PRIx64, len); xmlTextWriterWriteFormatRaw(writer, "0x%" PRIx32, crcs[index]); xmlTextWriterEndElement(writer); /* End crc */ From 376ef75964e7e200e9c5d39400c58cdc53b6a03a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 6 Jan 2023 16:06:51 +0100 Subject: [PATCH 10/18] Correctly implement LMA calculation. --- src/elfpatch.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/elfpatch.c b/src/elfpatch.c index 100f60f..d98823e 100644 --- a/src/elfpatch.c +++ b/src/elfpatch.c @@ -272,7 +272,8 @@ static int elf_patch_read_program_headers(elfpatch_handle_t *ep) print_err("Error reading program header (%zu): %s\n", i, elf_errmsg(-1)); goto ret_free_err; } - print_debug("Program Header (i): mem_size: %zu, file_size: %zu, vma: %p, lma: %p, file offset: %zu\n", + print_debug("Program Header (%zu): mem_size: %zu, file_size: %zu, vma: %p, lma: %p, file offset: %zu\n", + i, (size_t)hdr->p_memsz, (size_t)hdr->p_filesz, (void *)hdr->p_vaddr, (void *)hdr->p_paddr, hdr->p_offset); } @@ -291,11 +292,37 @@ ret_free_err: static void resolve_section_lmas(elfpatch_handle_t *ep) { SlList *sec_iter; + struct elf_section *sec; + size_t idx; + uint64_t sec_file_offset; + uint64_t section_offset_in_segment; + const GElf_Phdr *phdr; ret_if_ep_err(ep); for (sec_iter = ep->sections; sec_iter; sec_iter = sl_list_next(sec_iter)) { + sec = (struct elf_section *)sec_iter->data; + if (!sec) + continue; + if (sec->section_header.sh_type == SHT_NOBITS) { + /* Section does not contain data. It may be allocated but is not loaded. Therefore, LMA=VMA. */ + sec->lma = (uint64_t)sec->section_header.sh_addr; + continue; + } + + sec_file_offset = (uint64_t) sec->section_header.sh_offset; + + /* Check in which segment the file offset is located */ + for (idx = 0; idx < ep->program_headers_count; idx++) { + phdr = &ep->program_headers[idx]; + if (sec_file_offset >= phdr->p_offset && sec_file_offset < (phdr->p_offset + phdr->p_filesz)) { + /* Section lies within this segment */ + section_offset_in_segment = sec_file_offset - phdr->p_offset; + sec->lma = ((uint64_t)phdr->p_paddr) + section_offset_in_segment; + break; + } + } } } From 1528700d31abec6e74f1c18ce9c247fcf9010214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 6 Jan 2023 16:17:55 +0100 Subject: [PATCH 11/18] Add reading of LMA --- src/elfpatch.c | 4 ++-- src/xml.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/elfpatch.c b/src/elfpatch.c index d98823e..709918b 100644 --- a/src/elfpatch.c +++ b/src/elfpatch.c @@ -708,9 +708,9 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, needed_space = calculate_needed_space_for_crcs(ep, format, check_start_magic, check_end_magic, crc_size_bytes, crc_count); - print_debug("Required space for %zu CRCs %s: %zu (available: %zu)\n", + print_debug("Required space for %zu CRCs%s: %zu (available: %zu)\n", crc_count, - (check_start_magic || check_end_magic ? "including magic values" : ""), + (check_start_magic || check_end_magic ? " including magic values" : ""), needed_space, output_sec_data->d_size ); diff --git a/src/xml.c b/src/xml.c index 4ed7af6..a68e4bd 100644 --- a/src/xml.c +++ b/src/xml.c @@ -405,9 +405,8 @@ struct xml_crc_import *xml_import_from_file(const char *path) ret->xml_crc_entries = sl_list_append(ret->xml_crc_entries, crc); get_uint64_from_node_attribute(current_node, "vma", &tmp_num64); - printf("vma: %x\n", (uint32_t)tmp_num64); get_uint64_from_node_attribute(current_node, "size", &tmp_num64); - printf("size: %x\n", (uint32_t)tmp_num64); + get_uint64_from_node_attribute(current_node, "lma", &tmp_num64); } From 1d5219cc1813326718e6416c464f29762695f94c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 6 Jan 2023 16:25:59 +0100 Subject: [PATCH 12/18] Add print_warn() macro and the --use-vma option --- include/patchelfcrc/reporting.h | 3 ++- man/patchelfcrc.1.md | 5 ++++- src/main.c | 15 +++++++++++++-- src/xml.c | 6 +++--- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/include/patchelfcrc/reporting.h b/include/patchelfcrc/reporting.h index ff682e8..e6a3cb2 100644 --- a/include/patchelfcrc/reporting.h +++ b/include/patchelfcrc/reporting.h @@ -21,7 +21,8 @@ #include -#define print_err(fmt, ...) fprintf(stderr, "[ERR] " fmt, ## __VA_ARGS__); +#define print_err(fmt, ...) fprintf(stderr, "[ERR] " fmt, ## __VA_ARGS__) +#define print_warn(fmt, ...) fprintf(stderr, "[WARN] " fmt, ## __VAR__ARGS__) void print_debug(const char *fmt, ...); diff --git a/man/patchelfcrc.1.md b/man/patchelfcrc.1.md index 63cdf7a..89ae5e9 100644 --- a/man/patchelfcrc.1.md +++ b/man/patchelfcrc.1.md @@ -11,7 +11,7 @@ [**\--granularity**=*GRANULARITY*] [**\--little-endian**] [**\--dry-run**] [**\--xsd**] [**\--poly**=*POLYNOMIAL*] [**\--reversed**] [**\--start-value**=*STARTVALUE*] [**--verbose**] [**\--xor-out**=*XORVAL*] [**\--end-magic**=*MAGIC*] -[**\--crc-format**=*FORMAT*] [**\--list-crcs**] [**\--output-section**=*OUTPUTSECTION*] +[**\--crc-format**=*FORMAT*] [**\--use-vma**] [**\--list-crcs**] [**\--output-section**=*OUTPUTSECTION*] [**\--start-magic**=*MAGIC*] [**\--section**=*SECTION*] [**\--help**] [**\--usage**] [**\--version**] *ELF* @@ -50,6 +50,9 @@ **-F** *FORMAT*, **\--crc-format**=*FORMAT* : Output format to place in output section. Options for *FORMAT* are *bare* or *struct* +**--use_vma** +: Use the virtual memory address (VMA) instead of the load memory address (LMA) for the address fields in the struct output. This option is only considered if the format is *struct* + **--start-magic**=*MAGIC*, **--endmagic**=*MAGIC* : *MAGIC* numbers (32 bit unsigned) that are expected to be found at the start and the end of the given output section. This serves as safety guard against accidental corruption of the output file. *It is highly recommended to use these options*. diff --git a/src/main.c b/src/main.c index c50a441..3a6e7da 100644 --- a/src/main.c +++ b/src/main.c @@ -38,13 +38,15 @@ const char *argp_program_bug_address = "print_xsd = true; break; + case ARG_KEY_USE_VMA: + args->use_vma = true; + break; case 'p': /* Polyniomial */ args->crc.polynomial = strtoull(arg, &endptr, 0); @@ -189,6 +194,7 @@ static int parse_cmdline_options(int *argc, char ***argv, struct command_line_op {"export", ARG_KEY_EXPORT, "XML", 0, "Export CRCs to XML file", 3}, {"import", ARG_KEY_IMPORT, "XML", 0, "Do not caclulate CRCs but import them from file", 3}, {"xsd", ARG_KEY_XSD, 0, 0, "Print XSD to stdout", 0}, + {"use-vma", ARG_KEY_USE_VMA, 0, 0, "Use the VMA instead of the LMA for struct output", 2}, /* Sentinel */ {NULL, 0, 0, 0, NULL, 0} }; @@ -214,6 +220,7 @@ static void prepare_default_opts(struct command_line_options *opts) opts->granularity = GRANULARITY_BYTE; opts->dry_run = false; opts->crc.xor = 0UL; + opts->use_vma = false; opts->crc.polynomial = 0x104C11DB7UL; opts->crc.start_value = 0xFFFFFFFFUL; opts->crc.rev = false; @@ -308,7 +315,7 @@ static int check_all_sections_present(elfpatch_handle_t *ep, SlList *list) if (!ep) return -1001; if (!list) { - print_err("No input sections specified.\n") + print_err("No input sections specified.\n"); return -1; } for (iter = list; iter; iter = sl_list_next(iter)) { @@ -426,6 +433,10 @@ int main(int argc, char **argv) return -2; } + if (cmd_opts.use_vma && cmd_opts.format != FORMAT_STRUCT) { + print_warn("--use-vma option only has an effect when exporting as struct output."); + } + if (!cmd_opts.output_section && cmd_opts.export_xml == NULL) { print_err("No output section / XML export specified. Will continue but not create any output\n"); } diff --git a/src/xml.c b/src/xml.c index a68e4bd..2ead328 100644 --- a/src/xml.c +++ b/src/xml.c @@ -39,8 +39,8 @@ int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *secti writer = xmlNewTextWriterFilename(path, 0); if (!writer) { - print_err("Cannot create XML file %s\n", path) - ret = -1; + print_err("Cannot create XML file %s\n", path); + ret = -1; goto ret_none; } @@ -393,7 +393,7 @@ struct xml_crc_import *xml_import_from_file(const char *path) /* Get all CRCs */ xpath_obj = xmlXPathEvalExpression(BAD_CAST "/patchelfcrc/sections/crc", xpath_ctx); if (xmlXPathNodeSetIsEmpty(xpath_obj->nodesetval)) { - print_err("Internal error during read\n") + print_err("Internal error during read\n"); xml_crc_import_free(ret); ret = NULL; goto ret_close_doc; From 5134d1b9745f7ce7611d02a6908c83636fb040c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 6 Jan 2023 16:33:25 +0100 Subject: [PATCH 13/18] Fix print_warn() macro --- include/patchelfcrc/reporting.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/patchelfcrc/reporting.h b/include/patchelfcrc/reporting.h index e6a3cb2..73ceef6 100644 --- a/include/patchelfcrc/reporting.h +++ b/include/patchelfcrc/reporting.h @@ -22,7 +22,8 @@ #include #define print_err(fmt, ...) fprintf(stderr, "[ERR] " fmt, ## __VA_ARGS__) -#define print_warn(fmt, ...) fprintf(stderr, "[WARN] " fmt, ## __VAR__ARGS__) + +#define print_warn(fmt, ...) fprintf(stderr, "[WARN] " fmt, ## __VA_ARGS__) void print_debug(const char *fmt, ...); From 06fe82b2f1c53196c52d06419527b871b93c06d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 6 Jan 2023 16:37:33 +0100 Subject: [PATCH 14/18] Add missing newline to error prints --- src/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index 3a6e7da..5a51a2f 100644 --- a/src/main.c +++ b/src/main.c @@ -429,12 +429,12 @@ int main(int argc, char **argv) } if (cmd_opts.export_xml && cmd_opts.import_xml) { - print_err("XML export and input cannot be specified at the same time."); + print_err("XML export and input cannot be specified at the same time.\n"); return -2; } if (cmd_opts.use_vma && cmd_opts.format != FORMAT_STRUCT) { - print_warn("--use-vma option only has an effect when exporting as struct output."); + print_warn("--use-vma option only has an effect when exporting as struct output.\n"); } if (!cmd_opts.output_section && cmd_opts.export_xml == NULL) { From e93b42dd4045a5746e82c40b6dba6369a7cfff00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 6 Jan 2023 17:30:37 +0100 Subject: [PATCH 15/18] Make name of sections in XML file a necessary string with a minimum length of 1 --- resources/schema.xsd | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/schema.xsd b/resources/schema.xsd index 89c2d3f..4bba0e2 100644 --- a/resources/schema.xsd +++ b/resources/schema.xsd @@ -48,7 +48,13 @@ - + + + + + + + From aa15e1a541d50cad72e9f4edd89fffae3507ca45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 6 Jan 2023 17:32:51 +0100 Subject: [PATCH 16/18] Read section name from XML --- include/patchelfcrc/xml.h | 2 ++ src/xml.c | 54 +++++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/include/patchelfcrc/xml.h b/include/patchelfcrc/xml.h index 6cd4e24..08265ab 100644 --- a/include/patchelfcrc/xml.h +++ b/include/patchelfcrc/xml.h @@ -7,7 +7,9 @@ #include struct xml_crc_entry { + char *name; uint64_t vma; + uint64_t lma; uint64_t size; uint32_t crc; }; diff --git a/src/xml.c b/src/xml.c index 2ead328..1a7bb0a 100644 --- a/src/xml.c +++ b/src/xml.c @@ -296,7 +296,7 @@ int get_uint64_from_node_attribute(xmlNodePtr node, const char *attr, uint64_t * return ret; } -int get_uint32_from_node_attribute(xmlNodePtr node, const char *attr, uint32_t *output) +static int get_uint32_from_node_attribute(xmlNodePtr node, const char *attr, uint32_t *output) { int ret; uint64_t tmp = 0; @@ -304,7 +304,7 @@ int get_uint32_from_node_attribute(xmlNodePtr node, const char *attr, uint32_t * ret = get_uint64_from_node_attribute(node, attr, &tmp); if (tmp > UINT32_MAX || ret) { - print_err("Cannot conver attribute %s to number\n", attr); + print_err("Cannot convert attribute %s to 32 bit number\n", attr); ret = -1; } else { *output = (uint32_t)tmp; @@ -313,6 +313,39 @@ int get_uint32_from_node_attribute(xmlNodePtr node, const char *attr, uint32_t * return ret; } +static int get_uint64_from_node_content(xmlNodePtr node, uint64_t *output) +{ + xmlChar *data; + int ret = -1; + + data = xmlNodeGetContent(node); + + if (data) { + ret = convert_number_string_to_uint((const char *)data, output); + xmlFree(data); + } + + return ret; +} + +static int get_uint32_from_node_content(xmlNodePtr node, uint32_t *output) +{ + int ret; + uint64_t tmp = 0; + + ret = get_uint64_from_node_content(node, &tmp); + + if (tmp > UINT32_MAX || ret) { + print_err("Cannot convert content to 32 bit number\n"); + ret = -1; + } else { + *output = (uint32_t)tmp; + } + + return ret; +} + + struct xml_crc_import *xml_import_from_file(const char *path) { struct xml_crc_import *ret = NULL; @@ -405,12 +438,17 @@ struct xml_crc_import *xml_import_from_file(const char *path) ret->xml_crc_entries = sl_list_append(ret->xml_crc_entries, crc); get_uint64_from_node_attribute(current_node, "vma", &tmp_num64); + crc->vma = tmp_num64; get_uint64_from_node_attribute(current_node, "size", &tmp_num64); + crc->size = tmp_num64; get_uint64_from_node_attribute(current_node, "lma", &tmp_num64); + crc->lma = tmp_num64; + get_uint32_from_node_content(current_node, &tmp_num32); + crc->crc = tmp_num32; + crc->name = (char *)xmlGetProp(current_node, "name"); } - ret_close_doc: if (xpath_obj) @@ -429,9 +467,15 @@ ret_none: } -static void free_xml_crc_entry(void *entry) { - if (entry) +static void free_xml_crc_entry(void *entry) +{ + struct xml_crc_entry *e = (struct xml_crc_entry *)entry; + + if (entry) { + if (e->name) + xmlFree(e->name); free(entry); + } } void xml_crc_import_free(struct xml_crc_import *data) From c41214fc75d3deca170bd97457158adba271524f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 6 Jan 2023 18:43:47 +0100 Subject: [PATCH 17/18] Finish import/export functionality --- include/patchelfcrc/crc-datatypes.h | 20 ++++++ include/patchelfcrc/elfpatch.h | 19 ++---- include/patchelfcrc/xml.h | 26 ++------ src/elfpatch.c | 88 +++++++++++++------------- src/main.c | 96 +++++++++++++++++------------ src/xml.c | 73 ++++++++++------------ 6 files changed, 165 insertions(+), 157 deletions(-) create mode 100644 include/patchelfcrc/crc-datatypes.h diff --git a/include/patchelfcrc/crc-datatypes.h b/include/patchelfcrc/crc-datatypes.h new file mode 100644 index 0000000..9aec689 --- /dev/null +++ b/include/patchelfcrc/crc-datatypes.h @@ -0,0 +1,20 @@ +#ifndef _ELFPATCHCRC_DATATYPES_H_ +#define _ELFPATCHCRC_DATATYPES_H_ + +#include + +struct crc_entry { + char *name; + uint64_t vma; + uint64_t lma; + uint64_t size; + uint32_t crc; +}; + +struct crc_import_data { + int elf_bits; + struct crc_settings crc_config; + SlList *crc_entries; /**< @brief linked list of @ref crc_entry structs */ +}; + +#endif /* _ELFPATCHCRC_DATATYPES_H_ */ diff --git a/include/patchelfcrc/elfpatch.h b/include/patchelfcrc/elfpatch.h index 4d5b778..32a9014 100644 --- a/include/patchelfcrc/elfpatch.h +++ b/include/patchelfcrc/elfpatch.h @@ -27,6 +27,7 @@ #include #include #include +#include typedef struct elfpatch elfpatch_handle_t; @@ -87,17 +88,9 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio void elf_patch_close_and_free(elfpatch_handle_t *ep); -/** - * @brief Write CRCs to output section. This will have no effect, if file is opened read onyl - * @param ep Elf patch object - * @param[in] section Section name to place CRCs in - * @param[in] section_name_list The list of sections the data belongs to - * @param[in] crcs CRCs. Must be of the same lenght as the \p section_name_list - * @return 0 Success - * @return -1000 Parameter error - * @return -1 internal error - */ -int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, const SlList *section_name_list, - const uint32_t *crcs, uint8_t crc_size_bits, uint32_t start_magic, uint32_t end_magic, - bool check_start_magic, bool check_end_magic, enum crc_format format, bool little_endian); +int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *output_sec_name, + const struct crc_import_data *crc_data, bool use_vma, + uint32_t start_magic, uint32_t end_magic, + bool check_start_magic, bool check_end_magic, + enum crc_format format, bool little_endian); #endif /* _ELFPATCH_H_ */ diff --git a/include/patchelfcrc/xml.h b/include/patchelfcrc/xml.h index 08265ab..69211c6 100644 --- a/include/patchelfcrc/xml.h +++ b/include/patchelfcrc/xml.h @@ -1,29 +1,13 @@ #ifndef _ELFPATCHCRC_XML_H_ #define _ELFPATCHCRC_XML_H_ -#include #include #include -#include - -struct xml_crc_entry { - char *name; - uint64_t vma; - uint64_t lma; - uint64_t size; - uint32_t crc; -}; - -struct xml_crc_import { - int elf_bits; - struct crc_settings crc_config; - SlList *xml_crc_entries; /**< @brief linked list of @ref xml_crc_entry structs */ -}; +#include void xml_init(void); -int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *section_names, - const struct crc_settings *crc_params, elfpatch_handle_t *ep); +int xml_write_crcs_to_file(const char *path, const struct crc_import_data *crc_data); /** * @brief xml_import_from_file Import from file @@ -31,17 +15,19 @@ int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *secti * @return Returns a newly allocated struct. Must be freed with @ref xml_crc_import_free * @return NULL in case of error */ -struct xml_crc_import *xml_import_from_file(const char *path); +struct crc_import_data *xml_import_from_file(const char *path); /** * @brief Fully free supplied import data * @param data Data to free */ -void xml_crc_import_free(struct xml_crc_import *data); +void xml_crc_import_free(struct crc_import_data *data); /** * @brief Print XML XSD file to stdout */ void xml_print_xsd(void); +struct crc_import_data *xml_crc_import_alloc(void); + #endif /* _ELFPATCHCRC_XML_H_ */ diff --git a/src/elfpatch.c b/src/elfpatch.c index 709918b..807639b 100644 --- a/src/elfpatch.c +++ b/src/elfpatch.c @@ -574,8 +574,8 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio return 0; } -static size_t calculate_needed_space_for_crcs(elfpatch_handle_t *ep, - enum crc_format format, +static size_t calculate_needed_space_for_crcs(enum crc_format format, + uint8_t source_elf_bits, bool check_start_magic, bool check_end_magic, uint8_t crc_size_bytes, size_t crc_count) { @@ -588,7 +588,7 @@ static size_t calculate_needed_space_for_crcs(elfpatch_handle_t *ep, case FORMAT_STRUCT: /* Calculate space for CRCs including sentinel struct at the end */ needed_space = (crc_count + 1) * - (ep->class == ELFCLASS32 + (source_elf_bits == 32 ? sizeof(struct crc_out_struct_32bit) : sizeof(struct crc_out_struct_64bit)); break; @@ -599,8 +599,8 @@ static size_t calculate_needed_space_for_crcs(elfpatch_handle_t *ep, /* Add existing magic numbers to required space */ if (check_start_magic) { needed_space += 4u; - /* Account for paading after 32 bit magic value in case of structure usage on 64 bit systems */ - if (ep->class == ELFCLASS64 && format == FORMAT_STRUCT) + /* Account for padding after 32 bit magic value in case of structure usage on 64 bit systems */ + if (source_elf_bits == 64 && format == FORMAT_STRUCT) needed_space += 4u; } if (check_end_magic) @@ -629,13 +629,15 @@ static void get_section_load_addr(const struct elf_section *sec, uint64_t *lma) } -int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, const SlList *section_name_list, - const uint32_t *crcs, uint8_t crc_size_bits, uint32_t start_magic, uint32_t end_magic, - bool check_start_magic, bool check_end_magic, enum crc_format format, bool little_endian) +int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *output_sec_name, + const struct crc_import_data *crc_data, bool use_vma, + uint32_t start_magic, uint32_t end_magic, + bool check_start_magic, bool check_end_magic, + enum crc_format format, bool little_endian) { int ret = -1; + uint8_t crc_size_bits; struct elf_section *output_section; - struct elf_section *input_section; Elf_Data *output_sec_data; const SlList *iter; size_t needed_space; @@ -643,25 +645,29 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, uint8_t crc_size_bytes; uint8_t *sec_bytes; size_t idx; + struct crc_entry *crc_entry; struct crc_out_struct_32bit crc_32bit; struct crc_out_struct_64bit crc_64bit; + uint64_t in_sec_addr, in_sec_len; ret_val_if_ep_err(ep, -1000); print_debug("== Patch output file ==\n"); + crc_size_bits = crc_len_from_poly(crc_data->crc_config.polynomial); + if (crc_size_bits < 1u || crc_size_bits > 32u) { print_err("Unsupported CRC size: %u", (unsigned int)crc_size_bits); return -1; } /* All pointer parameters are required */ - if (!section || !section_name_list || !crcs) + if (!output_sec_name || !crc_data) return -1000; - output_section = find_section_in_list(ep->sections, section); + output_section = find_section_in_list(ep->sections, output_sec_name); if (!output_section) { - print_err("Cannot find output section '%s' to place CRCs. Exiting.\n", section); + print_err("Cannot find output section '%s' to place CRCs. Exiting.\n", output_sec_name); goto ret_err; } @@ -669,8 +675,8 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, output_sec_data = elf_getdata(output_section->scn, NULL); sec_bytes = (uint8_t *)output_sec_data->d_buf; if (!sec_bytes) { - print_err("Output section '%s' does not contain loadable data. It has to be allocated in the ELF file\n", - section); + print_err("Output section '%s' does not contain loadable data. It has to be allocated in the ELF file.\n", + output_sec_name); goto ret_err; } @@ -695,17 +701,17 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, /* Calculate Bytes needed for CRC */ crc_size_bytes = (crc_size_bits + 7u) / 8u; - crc_count = sl_list_length(section_name_list); + crc_count = sl_list_length(crc_data->crc_entries); if (crc_count < 1) { /* No CRCs to patch... */ ret = -1; - print_err("No CRCs to patch. This is probably an internal error.\n"); + print_err("No CRCs to patch.\n"); goto ret_err; } print_debug("Single CRC requires %u bytes.\n", (unsigned int)crc_size_bytes); - needed_space = calculate_needed_space_for_crcs(ep, format, check_start_magic, check_end_magic, crc_size_bytes, + needed_space = calculate_needed_space_for_crcs(format, crc_data->elf_bits, check_start_magic, check_end_magic, crc_size_bytes, crc_count); print_debug("Required space for %zu CRCs%s: %zu (available: %zu)\n", @@ -726,44 +732,42 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, if (format == FORMAT_BARE) { if (check_start_magic) sec_bytes += 4u; - for (iter = section_name_list, idx = 0; iter; iter = sl_list_next(iter), idx++) { - print_debug("Write CRC 0x%08x (%u bytes) for section %s\n", crcs[idx], - (unsigned int)crc_size_bytes, - iter->data); - write_crc_to_byte_array(sec_bytes, crcs[idx], crc_size_bytes, little_endian); + for (iter = crc_data->crc_entries, idx = 0; iter; iter = sl_list_next(iter), idx++) { + crc_entry = (struct crc_entry *)iter->data; + print_debug("Write CRC 0x%08x (%u bytes) for section %s\n", crc_entry->crc, + (unsigned int)crc_size_bytes, + crc_entry->name); + write_crc_to_byte_array(sec_bytes, crc_entry->crc, crc_size_bytes, little_endian); sec_bytes += crc_size_bytes; } } else if (format == FORMAT_STRUCT) { if (check_start_magic) sec_bytes += 4u; - if (check_start_magic && ep->class == ELFCLASS64) + if (check_start_magic && crc_data->elf_bits == 64) sec_bytes += 4u; - for (iter = section_name_list, idx = 0; iter; iter = sl_list_next(iter), idx++) { - input_section = find_section_in_list(ep->sections, (const char *)iter->data); - if (!input_section) { - print_err("Internal error. Please report this. %s:%d ", __FILE__, __LINE__); - ret = -2; - goto ret_err; - } - print_debug("Write CRC 0x%08x (%u bytes) for section %s.\n", crcs[idx], + for (iter = crc_data->crc_entries, idx = 0; iter; iter = sl_list_next(iter), idx++) { + crc_entry = (struct crc_entry *)iter->data; + in_sec_addr = use_vma ? crc_entry->vma : crc_entry->lma; + in_sec_len = crc_entry->size; + print_debug("Write CRC 0x%08x (%u bytes) for section %s.\n", crc_entry->crc, (unsigned int)crc_size_bytes, - iter->data); + crc_entry->name); print_debug("Corresponding input section at 0x%"PRIx64", length: %"PRIu64"\n", - (uint64_t)input_section->section_header.sh_addr, - (uint64_t)input_section->section_header.sh_size); - if (ep->class == ELFCLASS32) { - crc_32bit.crc = crcs[idx]; - crc_32bit.length = (uint32_t)input_section->section_header.sh_size; - crc_32bit.start_address = (uint32_t)input_section->section_header.sh_addr; + in_sec_addr, + in_sec_len); + if (crc_data->elf_bits == 32) { + crc_32bit.crc = crc_entry->crc; + crc_32bit.length = (uint32_t)in_sec_len; + crc_32bit.start_address = (uint32_t)in_sec_addr; memcpy(sec_bytes, &crc_32bit, sizeof(crc_32bit)); sec_bytes += sizeof(crc_32bit); } else { /* 64 bit case */ - crc_64bit.crc = crcs[idx]; + crc_64bit.crc = crc_entry->crc; crc_64bit._unused_dummy = 0ul; - crc_64bit.length = (uint64_t)input_section->section_header.sh_size; - crc_64bit.start_address = (uint64_t)input_section->section_header.sh_addr; + crc_64bit.length = in_sec_len; + crc_64bit.start_address = in_sec_addr; memcpy(sec_bytes, &crc_64bit, sizeof(crc_64bit)); sec_bytes += sizeof(crc_64bit); } @@ -778,7 +782,7 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, crc_64bit.length = 0ull; crc_64bit.start_address = 0ull; - if (ep->class == ELFCLASS32) { + if (crc_data->elf_bits == 32) { memcpy(sec_bytes, &crc_32bit, sizeof(crc_32bit)); } else { memcpy(sec_bytes, &crc_64bit, sizeof(crc_64bit)); diff --git a/src/main.c b/src/main.c index 5a51a2f..949b45a 100644 --- a/src/main.c +++ b/src/main.c @@ -338,31 +338,49 @@ static int check_all_sections_present(elfpatch_handle_t *ep, SlList *list) * @param ep Elf patch * @param list List of section names to patch * @param opts Command line options. Used for CRC generation - * @param[out] crcs Array of output CRCs. Must be large enough to hold all elements - * @return 0 if successful + * @return CRC data */ -static int compute_crcs(elfpatch_handle_t *ep, SlList *list, const struct command_line_options *opts, uint32_t *crcs) +static struct crc_import_data *compute_crcs(elfpatch_handle_t *ep, SlList *list, const struct command_line_options *opts) { SlList *iter; const char *sec_name; - int ret = 0; + struct crc_import_data *ret = NULL; + struct crc_entry *entry; struct crc_calc _crc; struct crc_calc * const crc = &_crc; unsigned int idx; + uint64_t vma, lma, len; /* Construct the CRC */ crc_init(crc, &opts->crc); + ret = xml_crc_import_alloc(); + ret->elf_bits = elf_patch_get_bits(ep); + memcpy(&ret->crc_config, &opts->crc, sizeof(struct crc_settings)); + for (iter = list, idx = 0; iter; iter = sl_list_next(iter), idx++) { crc_reset(crc); sec_name = (const char *)iter->data; if (elf_patch_compute_crc_over_section(ep, sec_name, crc, opts->granularity, opts->little_endian)) { print_err("Error during CRC calculation. Exiting.\n"); - ret = -1; + xml_crc_import_free(ret); + ret = NULL; break; } crc_finish_calc(crc); - crcs[idx] = crc_get_value(crc); + if (elf_patch_get_section_address(ep, sec_name, &vma, &lma, &len)) { + print_err("Cannot retrieve section addresses. Internal error. Exiting.\n"); + xml_crc_import_free(ret); + ret = NULL; + break; + } + entry = (struct crc_entry *)malloc(sizeof(struct crc_entry)); + entry->name = strdup(sec_name); + entry->crc = crc_get_value(crc); + entry->lma = lma; + entry->size = len; + entry->vma = vma; + ret->crc_entries = sl_list_append(ret->crc_entries, entry); } crc_destroy(crc); @@ -371,16 +389,14 @@ static int compute_crcs(elfpatch_handle_t *ep, SlList *list, const struct comman /** * @brief Debug-print the CRCs of sections in form of a table - * @param[in] list List of section names - * @param[in] crcs Array of CRCs. + * @param[in] crc_data CRC data structure containing the CRCs. * @note The array @p crcs must be at least as long as @p list */ -static void print_crcs(SlList *list, const uint32_t *crcs) +static void print_crcs(const struct crc_import_data *crc_data) { SlList *iter; - unsigned int idx; - const char *sec_name; ft_table_t *table; + const struct crc_entry *entry; table = ft_create_table(); @@ -388,9 +404,9 @@ static void print_crcs(SlList *list, const uint32_t *crcs) ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER); ft_write_ln(table, "Section", "CRC"); - for (iter = list, idx = 0; iter; iter = sl_list_next(iter), idx++) { - sec_name = (const char *)iter->data; - ft_printf_ln(table, "%s|0x%x", sec_name, crcs[idx]); + for (iter = crc_data->crc_entries; iter; iter = sl_list_next(iter)) { + entry = (const struct crc_entry *)iter->data; + ft_printf_ln(table, "%s|0x%x", entry->name, entry->crc); } print_debug("Calculated CRCs:\n%s\n", ft_to_string(table)); ft_destroy_table(table); @@ -401,8 +417,7 @@ int main(int argc, char **argv) struct command_line_options cmd_opts; elfpatch_handle_t *ep; int ret = 0; - uint32_t *crcs = NULL; - struct xml_crc_import *import_data = NULL; + struct crc_import_data *crc_data = NULL; xml_init(); @@ -457,40 +472,41 @@ int main(int argc, char **argv) goto free_cmds; } - /* Check if all sections are present */ - if (check_all_sections_present(ep, cmd_opts.section_list)) { - ret = -2; - goto ret_close_elf; - } + if (!cmd_opts.import_xml) { + /* Check if all sections are present */ + if (check_all_sections_present(ep, cmd_opts.section_list)) { + ret = -2; + goto ret_close_elf; + } - /* Compute CRCs over sections */ - crcs = (uint32_t *)malloc(sl_list_length(cmd_opts.section_list) * sizeof(uint32_t)); - if (compute_crcs(ep, cmd_opts.section_list, &cmd_opts, crcs)) { - goto ret_close_elf; - } + /* Compute CRCs over sections */ + crc_data = compute_crcs(ep, cmd_opts.section_list, &cmd_opts); + if (!crc_data) { + goto ret_close_elf; + } - if (reporting_get_verbosity()) { - print_crcs(cmd_opts.section_list, crcs); + if (reporting_get_verbosity()) { + print_crcs(crc_data); + } + } else { + crc_data = xml_import_from_file(cmd_opts.import_xml); } if (cmd_opts.output_section) { - if (elf_patch_write_crcs_to_section(ep, cmd_opts.output_section, cmd_opts.section_list, - crcs, crc_len_from_poly(cmd_opts.crc.polynomial), - cmd_opts.start_magic, cmd_opts.end_magic, - cmd_opts.has_start_magic, cmd_opts.has_end_magic, - cmd_opts.format, cmd_opts.little_endian)) { + /* Construct data */ + + if (elf_patch_write_crcs_to_section(ep, cmd_opts.output_section, crc_data, cmd_opts.use_vma, + cmd_opts.start_magic, cmd_opts.end_magic, cmd_opts.has_end_magic, + cmd_opts.has_end_magic, cmd_opts.format, cmd_opts.little_endian)) { ret = -1; } } if (cmd_opts.export_xml) { - if (xml_write_crcs_to_file(cmd_opts.export_xml, crcs, cmd_opts.section_list, &cmd_opts.crc, ep)) { + if (xml_write_crcs_to_file(cmd_opts.export_xml, crc_data)) { print_err("Error during XML generation\n"); ret = -3; } - /* Fix this: */ - import_data = xml_import_from_file(cmd_opts.export_xml); - } ret_close_elf: @@ -500,10 +516,8 @@ free_cmds: free_cmd_args(&cmd_opts); /* Free CRCs if necessary */ - if (crcs) - free(crcs); - if (import_data) - xml_crc_import_free(import_data); + if (crc_data) + xml_crc_import_free(crc_data); return ret; } diff --git a/src/xml.c b/src/xml.c index 1a7bb0a..e585987 100644 --- a/src/xml.c +++ b/src/xml.c @@ -22,18 +22,15 @@ void xml_init(void) LIBXML_TEST_VERSION; } -int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *section_name_list, - const struct crc_settings *crc_params, elfpatch_handle_t *ep) +int xml_write_crcs_to_file(const char *path, const struct crc_import_data *crc_data) { int ret = 0; - int bitsize; xmlTextWriter *writer; - SlList *name_iter; - const char *section_name; + SlList *entry_iter; + const struct crc_entry *entry; size_t index; - uint64_t vma, len, lma; - if (!path || !crcs || !section_name_list || !crc_params || !ep) { + if (!path || !crc_data) { return -1000; } @@ -53,38 +50,32 @@ int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *secti xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "version", "%s", version_string); xmlTextWriterStartElement(writer, BAD_CAST "settings"); - xmlTextWriterWriteFormatElement(writer, BAD_CAST "poly", "0x%" PRIx64, crc_params->polynomial); - xmlTextWriterWriteFormatElement(writer, BAD_CAST "start", "0x%" PRIx32, crc_params->start_value); - if (crc_params->rev) { + xmlTextWriterWriteFormatElement(writer, BAD_CAST "poly", "0x%" PRIx64, crc_data->crc_config.polynomial); + xmlTextWriterWriteFormatElement(writer, BAD_CAST "start", "0x%" PRIx32, crc_data->crc_config.start_value); + if (crc_data->crc_config.rev) { xmlTextWriterStartElement(writer, BAD_CAST "rev"); xmlTextWriterEndElement(writer); } - xmlTextWriterWriteFormatElement(writer, BAD_CAST "xor", "0x%" PRIx32, crc_params->xor); - bitsize = elf_patch_get_bits(ep); - if (bitsize < 0) { + xmlTextWriterWriteFormatElement(writer, BAD_CAST "xor", "0x%" PRIx32, crc_data->crc_config.xor); + if (crc_data->elf_bits < 0) { print_err("Cannot determine ELF class. Generated XML will be faulty.\n"); ret |= -1; } - xmlTextWriterWriteFormatElement(writer, BAD_CAST "elfclass", "%d", bitsize); + xmlTextWriterWriteFormatElement(writer, BAD_CAST "elfclass", "%d", crc_data->elf_bits); xmlTextWriterEndElement(writer); /* End settings */ xmlTextWriterStartElement(writer, BAD_CAST "sections"); /* Output all section CRCs */ - for (name_iter = section_name_list, index = 0u; name_iter; name_iter = sl_list_next(name_iter), index++) { - section_name = (const char *)name_iter->data; + for (entry_iter = crc_data->crc_entries, index = 0u; entry_iter; entry_iter = sl_list_next(entry_iter), index++) { + entry = (const struct crc_entry *)entry_iter->data; xmlTextWriterStartElement(writer, BAD_CAST "crc"); - xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "name", "%s", section_name); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "name", "%s", entry->name); xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "index", "%zu", index); - if (elf_patch_get_section_address(ep, section_name, &vma, &lma, &len)) { - print_err("Could not retrieve section addresses / length of section '%s'. XML output will be faulty.\n", - section_name); - ret |= -1; - } - xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "vma", "0x%" PRIx64, vma); - xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "lma", "0x%" PRIx64, lma); - xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "size", "0x%" PRIx64, len); - xmlTextWriterWriteFormatRaw(writer, "0x%" PRIx32, crcs[index]); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "vma", "0x%" PRIx64, entry->vma); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "lma", "0x%" PRIx64, entry->lma); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "size", "0x%" PRIx64, entry->size); + xmlTextWriterWriteFormatRaw(writer, "0x%" PRIx32, entry->crc); xmlTextWriterEndElement(writer); /* End crc */ } xmlTextWriterEndElement(writer); /* End sections */ @@ -98,13 +89,13 @@ ret_none: return ret; } -static struct xml_crc_import *xml_crc_import_alloc(void) +struct crc_import_data *xml_crc_import_alloc(void) { - struct xml_crc_import *ret = NULL; + struct crc_import_data *ret = NULL; - ret = (struct xml_crc_import *)malloc(sizeof(struct xml_crc_import)); + ret = (struct crc_import_data *)malloc(sizeof(struct crc_import_data)); if (ret) - ret->xml_crc_entries = NULL; + ret->crc_entries = NULL; else print_err("Error. Out of memory. This should never happen\n"); @@ -346,10 +337,10 @@ static int get_uint32_from_node_content(xmlNodePtr node, uint32_t *output) } -struct xml_crc_import *xml_import_from_file(const char *path) +struct crc_import_data *xml_import_from_file(const char *path) { - struct xml_crc_import *ret = NULL; - struct xml_crc_entry *crc; + struct crc_import_data *ret = NULL; + struct crc_entry *crc; xmlDocPtr doc; xmlNodePtr root_node; xmlNodePtr current_node; @@ -434,8 +425,8 @@ struct xml_crc_import *xml_import_from_file(const char *path) for (i = 0; i < xpath_obj->nodesetval->nodeNr; i++) { current_node = xpath_obj->nodesetval->nodeTab[i]; - crc = (struct xml_crc_entry *)malloc(sizeof(struct xml_crc_entry)); - ret->xml_crc_entries = sl_list_append(ret->xml_crc_entries, crc); + crc = (struct crc_entry *)malloc(sizeof(struct crc_entry)); + ret->crc_entries = sl_list_append(ret->crc_entries, crc); get_uint64_from_node_attribute(current_node, "vma", &tmp_num64); crc->vma = tmp_num64; @@ -446,7 +437,7 @@ struct xml_crc_import *xml_import_from_file(const char *path) get_uint32_from_node_content(current_node, &tmp_num32); crc->crc = tmp_num32; - crc->name = (char *)xmlGetProp(current_node, "name"); + crc->name = (char *)xmlGetProp(current_node, BAD_CAST "name"); } ret_close_doc: @@ -467,9 +458,9 @@ ret_none: } -static void free_xml_crc_entry(void *entry) +static void free_crc_entry(void *entry) { - struct xml_crc_entry *e = (struct xml_crc_entry *)entry; + struct crc_entry *e = (struct crc_entry *)entry; if (entry) { if (e->name) @@ -478,13 +469,13 @@ static void free_xml_crc_entry(void *entry) } } -void xml_crc_import_free(struct xml_crc_import *data) +void xml_crc_import_free(struct crc_import_data *data) { if (!data) return; - sl_list_free_full(data->xml_crc_entries, free_xml_crc_entry); - data->xml_crc_entries = NULL; + sl_list_free_full(data->crc_entries, free_crc_entry); + data->crc_entries = NULL; free(data); } From 2c39c8fd8f5e037600612ea123d8a88df2778596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 6 Jan 2023 18:49:59 +0100 Subject: [PATCH 18/18] Update man page --- man/patchelfcrc.1.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/man/patchelfcrc.1.md b/man/patchelfcrc.1.md index 89ae5e9..ca98945 100644 --- a/man/patchelfcrc.1.md +++ b/man/patchelfcrc.1.md @@ -12,6 +12,7 @@ [**\--poly**=*POLYNOMIAL*] [**\--reversed**] [**\--start-value**=*STARTVALUE*] [**--verbose**] [**\--xor-out**=*XORVAL*] [**\--end-magic**=*MAGIC*] [**\--crc-format**=*FORMAT*] [**\--use-vma**] [**\--list-crcs**] [**\--output-section**=*OUTPUTSECTION*] +[**\--export**=*XMLFILE*] [**\--import**=*XMLFILE*] [**\--start-magic**=*MAGIC*] [**\--section**=*SECTION*] [**\--help**] [**\--usage**] [**\--version**] *ELF* @@ -56,6 +57,12 @@ **--start-magic**=*MAGIC*, **--endmagic**=*MAGIC* : *MAGIC* numbers (32 bit unsigned) that are expected to be found at the start and the end of the given output section. This serves as safety guard against accidental corruption of the output file. *It is highly recommended to use these options*. +**--export**=*XMLFILE* +: Export the calculated files to an XML file *XMLFILE*. + +**--import**=*XMLFILE* +: Import the CRCs from an XML file *XMLFILE* and do not caclulate anything in the given *ELF* + **--help**, **-h**, **-?** : Print help.