Implement xml export / import #3
@ -26,6 +26,7 @@ find_package(PkgConfig REQUIRED)
|
|||||||
pkg_check_modules(ELF REQUIRED libelf)
|
pkg_check_modules(ELF REQUIRED libelf)
|
||||||
|
|
||||||
find_package(Doxygen)
|
find_package(Doxygen)
|
||||||
|
find_package(LibXml2 REQUIRED)
|
||||||
|
|
||||||
add_subdirectory(man)
|
add_subdirectory(man)
|
||||||
|
|
||||||
@ -47,9 +48,11 @@ set(FORT_ENABLE_TESTING OFF CACHE INTERNAL "")
|
|||||||
add_subdirectory(3rdparty/libfort)
|
add_subdirectory(3rdparty/libfort)
|
||||||
add_subdirectory(linklist-lib)
|
add_subdirectory(linklist-lib)
|
||||||
|
|
||||||
|
include_directories(${LIBXML2_INCLUDE_DIRS})
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${CFILES})
|
add_executable(${PROJECT_NAME} ${CFILES})
|
||||||
target_link_libraries(${PROJECT_NAME} ${ELF_LIBRARIES} fort linklist-lib)
|
target_link_libraries(${PROJECT_NAME} ${ELF_LIBRARIES} ${LIBXML2_LIBRARIES} fort linklist-lib)
|
||||||
target_link_directories(${PROJECT_NAME} PRIVATE ${ELF_LIBRARY_DIRS})
|
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 ${ELF_INCLUDE_DIRS})
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include")
|
target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include")
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE "include")
|
target_include_directories(${PROJECT_NAME} PRIVATE "include")
|
||||||
|
@ -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);
|
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
|
* @brief Compute CRC over a section in an ELF file
|
||||||
* @param ep Elf patch object
|
* @param ep Elf patch object
|
||||||
|
14
include/patchelfcrc/xml.h
Normal file
14
include/patchelfcrc/xml.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef _ELFPATCHCRC_XML_H_
|
||||||
|
#define _ELFPATCHCRC_XML_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <linklist-lib/singly-linked-list.h>
|
||||||
|
#include <patchelfcrc/crc.h>
|
||||||
|
#include <patchelfcrc/elfpatch.h>
|
||||||
|
|
||||||
|
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_ */
|
@ -482,6 +482,17 @@ static size_t calculate_needed_space_for_crcs(elfpatch_handle_t *ep,
|
|||||||
return needed_space;
|
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,
|
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,
|
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)
|
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);
|
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;
|
||||||
|
}
|
||||||
|
45
src/main.c
45
src/main.c
@ -27,6 +27,7 @@
|
|||||||
#include <linklist-lib/singly-linked-list.h>
|
#include <linklist-lib/singly-linked-list.h>
|
||||||
#include <patchelfcrc/reporting.h>
|
#include <patchelfcrc/reporting.h>
|
||||||
#include <patchelfcrc/elfpatch.h>
|
#include <patchelfcrc/elfpatch.h>
|
||||||
|
#include <patchelfcrc/xml.h>
|
||||||
#include <fort.h>
|
#include <fort.h>
|
||||||
|
|
||||||
const char *argp_program_bug_address = "<mario [dot] huettel [at] linux [dot] com>";
|
const char *argp_program_bug_address = "<mario [dot] huettel [at] linux [dot] com>";
|
||||||
@ -35,6 +36,8 @@ const char *argp_program_bug_address = "<mario [dot] huettel [at] linux [dot] co
|
|||||||
#define ARG_KEY_START_MAGIC (2)
|
#define ARG_KEY_START_MAGIC (2)
|
||||||
#define ARG_KEY_END_MAGIC (3)
|
#define ARG_KEY_END_MAGIC (3)
|
||||||
#define ARG_KEY_LIST (4)
|
#define ARG_KEY_LIST (4)
|
||||||
|
#define ARG_KEY_EXPORT (5)
|
||||||
|
#define ARG_KEY_IMPORT (6)
|
||||||
|
|
||||||
struct command_line_options {
|
struct command_line_options {
|
||||||
bool little_endian;
|
bool little_endian;
|
||||||
@ -51,6 +54,8 @@ struct command_line_options {
|
|||||||
SlList *section_list;
|
SlList *section_list;
|
||||||
const char *elf_path;
|
const char *elf_path;
|
||||||
const char *output_section;
|
const char *output_section;
|
||||||
|
const char *export_xml;
|
||||||
|
const char *import_xml;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,6 +85,12 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
|||||||
args->has_end_magic = true;
|
args->has_end_magic = true;
|
||||||
args->end_magic = strtoul(arg, NULL, 0);
|
args->end_magic = strtoul(arg, NULL, 0);
|
||||||
break;
|
break;
|
||||||
|
case ARG_KEY_EXPORT:
|
||||||
|
args->export_xml = arg;
|
||||||
|
break;
|
||||||
|
case ARG_KEY_IMPORT:
|
||||||
|
args->import_xml = arg;
|
||||||
|
break;
|
||||||
case ARG_KEY_LIST:
|
case ARG_KEY_LIST:
|
||||||
args->list = true;
|
args->list = true;
|
||||||
break;
|
break;
|
||||||
@ -144,7 +155,6 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
|||||||
return ARGP_ERR_UNKNOWN;
|
return ARGP_ERR_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,6 +181,8 @@ static int parse_cmdline_options(int *argc, char ***argv, struct command_line_op
|
|||||||
{"start-magic", ARG_KEY_START_MAGIC, "STARTMAGIC", 0, "Check output section for start magic (uint32)", 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},
|
{"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 */
|
/* Sentinel */
|
||||||
{NULL, 0, 0, 0, NULL, 0}
|
{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->section_list = NULL;
|
||||||
opts->elf_path = NULL;
|
opts->elf_path = NULL;
|
||||||
opts->output_section = 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)
|
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);
|
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) {
|
if (cmd_opts->section_list) {
|
||||||
for (list_iter = cmd_opts->section_list, i = 1; list_iter; list_iter = sl_list_next(list_iter), i++) {
|
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);
|
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);
|
crcs[idx] = crc_get_value(crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crc_destroy(crc);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,6 +389,8 @@ int main(int argc, char **argv)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
uint32_t *crcs;
|
uint32_t *crcs;
|
||||||
|
|
||||||
|
xml_init();
|
||||||
|
|
||||||
prepare_default_opts(&cmd_opts);
|
prepare_default_opts(&cmd_opts);
|
||||||
parse_cmdline_options(&argc, &argv, &cmd_opts);
|
parse_cmdline_options(&argc, &argv, &cmd_opts);
|
||||||
|
|
||||||
@ -384,8 +409,13 @@ int main(int argc, char **argv)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cmd_opts.output_section) {
|
if (cmd_opts.export_xml && cmd_opts.import_xml) {
|
||||||
print_err("No output section specified. Will continue but not patch file.\n");
|
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! */
|
/* 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 (cmd_opts.output_section) {
|
||||||
if (elf_patch_write_crcs_to_section(ep, cmd_opts.output_section, cmd_opts.section_list,
|
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.has_start_magic, cmd_opts.has_end_magic,
|
||||||
cmd_opts.format, cmd_opts.little_endian)) {
|
cmd_opts.format, cmd_opts.little_endian)) {
|
||||||
ret = -1;
|
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);
|
elf_patch_close_and_free(ep);
|
||||||
|
|
||||||
|
/* Free the CRCs. This is not strictly necessary... */
|
||||||
|
free(crcs);
|
||||||
free_cmds:
|
free_cmds:
|
||||||
|
|
||||||
free_cmd_args(&cmd_opts);
|
free_cmd_args(&cmd_opts);
|
||||||
|
74
src/xml.c
Normal file
74
src/xml.c
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#include <libxml/parser.h>
|
||||||
|
#include <libxml/xmlIO.h>
|
||||||
|
#include <libxml/xinclude.h>
|
||||||
|
#include <libxml/tree.h>
|
||||||
|
#include <libxml/encoding.h>
|
||||||
|
#include <libxml/xmlwriter.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <patchelfcrc/reporting.h>
|
||||||
|
#include <patchelfcrc/xml.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user