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; +}