Implement xml export / import #3
@ -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"
|
mkdir -p ${GEN_HEADER_PATH} && bash "${CMAKE_CURRENT_SOURCE_DIR}/gen_version_header.sh" "${GEN_HEADER_PATH}/version.h"
|
||||||
WORKING_DIRECTORY
|
WORKING_DIRECTORY
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${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)
|
add_compile_options(-Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter)
|
||||||
|
|
||||||
set(FORT_ENABLE_TESTING OFF CACHE INTERNAL "")
|
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 ${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")
|
||||||
add_dependencies(${PROJECT_NAME} version-header)
|
add_dependencies(${PROJECT_NAME} version-header schema-header)
|
||||||
|
|
||||||
if (DOXYGEN_FOUND)
|
if (DOXYGEN_FOUND)
|
||||||
set(DOXYFILE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/doxygen/Doxyfile.in")
|
set(DOXYFILE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/doxygen/Doxyfile.in")
|
||||||
|
@ -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);
|
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
|
* @brief Get VMA, LMA and size of section
|
||||||
* @param ep Elfpatch handle
|
* @param ep Elfpatch handle
|
||||||
|
@ -6,9 +6,35 @@
|
|||||||
#include <patchelfcrc/crc.h>
|
#include <patchelfcrc/crc.h>
|
||||||
#include <patchelfcrc/elfpatch.h>
|
#include <patchelfcrc/elfpatch.h>
|
||||||
|
|
||||||
|
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);
|
void xml_init(void);
|
||||||
|
|
||||||
int xml_write_crcs_to_file(const char *path, const uint32_t *crcs, SlList *section_names,
|
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);
|
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_ */
|
#endif /* _ELFPATCHCRC_XML_H_ */
|
||||||
|
38
resources/schema.xsd
Normal file
38
resources/schema.xsd
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||||
|
<xs:element name="patchelfcrc">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="settings">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element type="xs:string" name="poly"/>
|
||||||
|
<xs:element type="xs:string" name="start"/>
|
||||||
|
<xs:element type="xs:string" name="rev"/>
|
||||||
|
<xs:element type="xs:string" name="xor"/>
|
||||||
|
<xs:element type="xs:integer" name="elfclass"/>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
<xs:element name="sections">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:element name="crc">
|
||||||
|
<xs:complexType>
|
||||||
|
<xs:simpleContent>
|
||||||
|
<xs:extension base="xs:string">
|
||||||
|
<xs:attribute type="xs:string" name="name"/>
|
||||||
|
<xs:attribute type="xs:integer" name="index"/>
|
||||||
|
<xs:attribute type="xs:string" name="vma"/>
|
||||||
|
<xs:attribute type="xs:string" name="size"/>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:simpleContent>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:sequence>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute type="xs:string" name="version"/>
|
||||||
|
</xs:complexType>
|
||||||
|
</xs:element>
|
||||||
|
</xs:schema>
|
@ -702,3 +702,24 @@ int elf_patch_get_section_address(elfpatch_handle_t *ep, const char *section,
|
|||||||
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
@ -459,9 +459,14 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cmd_opts.export_xml) {
|
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);
|
elf_patch_close_and_free(ep);
|
||||||
|
|
||||||
/* Free the CRCs. This is not strictly necessary... */
|
/* Free the CRCs. This is not strictly necessary... */
|
||||||
|
161
src/xml.c
161
src/xml.c
@ -4,11 +4,14 @@
|
|||||||
#include <libxml/tree.h>
|
#include <libxml/tree.h>
|
||||||
#include <libxml/encoding.h>
|
#include <libxml/encoding.h>
|
||||||
#include <libxml/xmlwriter.h>
|
#include <libxml/xmlwriter.h>
|
||||||
|
#include <libxml/xmlreader.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <patchelfcrc/reporting.h>
|
#include <patchelfcrc/reporting.h>
|
||||||
#include <patchelfcrc/xml.h>
|
#include <patchelfcrc/xml.h>
|
||||||
|
#include <patchelfcrc/version.h>
|
||||||
|
#include <generated/schema-blob.h>
|
||||||
|
|
||||||
void xml_init(void)
|
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)
|
const struct crc_settings *crc_params, elfpatch_handle_t *ep)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
int bitsize;
|
||||||
xmlTextWriter *writer;
|
xmlTextWriter *writer;
|
||||||
SlList *name_iter;
|
SlList *name_iter;
|
||||||
const char *section_name;
|
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);
|
writer = xmlNewTextWriterFilename(path, 0);
|
||||||
if (!writer) {
|
if (!writer) {
|
||||||
print_err("Cannot create XML file %s\n", path)
|
print_err("Cannot create XML file %s\n", path)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto ret_none;
|
goto ret_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlTextWriterSetIndentString(writer, BAD_CAST "\t");
|
//xmlTextWriterSetIndentString(writer, BAD_CAST "\t");
|
||||||
xmlTextWriterSetIndent(writer, 1);
|
//xmlTextWriterSetIndent(writer, 1);
|
||||||
|
|
||||||
xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);
|
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");
|
xmlTextWriterStartElement(writer, BAD_CAST "settings");
|
||||||
xmlTextWriterWriteFormatElement(writer, BAD_CAST "poly", "0x%" PRIx64, crc_params->polynomial);
|
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 "start", "0x%" PRIx32, crc_params->start_value);
|
||||||
xmlTextWriterWriteFormatElement(writer, BAD_CAST "rev", "%s", crc_params->rev ? "true" : "false");
|
xmlTextWriterWriteFormatElement(writer, BAD_CAST "rev", "%s", crc_params->rev ? "true" : "false");
|
||||||
xmlTextWriterWriteFormatElement(writer, BAD_CAST "xor", "0x%" PRIx32, crc_params->xor);
|
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 */
|
xmlTextWriterEndElement(writer); /* End settings */
|
||||||
|
|
||||||
xmlTextWriterStartElement(writer, BAD_CAST "sections");
|
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)) {
|
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",
|
print_err("Could not retrieve section address / length of section '%s'. XML output will be faulty.\n",
|
||||||
section_name);
|
section_name);
|
||||||
|
ret |= -1;
|
||||||
}
|
}
|
||||||
xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "vma", "0x%" PRIx64, vma);
|
xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "vma", "0x%" PRIx64, vma);
|
||||||
xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "size", "0x%" PRIx64, len);
|
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 crc */
|
||||||
}
|
}
|
||||||
xmlTextWriterEndElement(writer); /* End sections */
|
xmlTextWriterEndElement(writer); /* End sections */
|
||||||
|
|
||||||
|
xmlTextWriterEndElement(writer); /* End root node */
|
||||||
|
|
||||||
xmlTextWriterEndDocument(writer);
|
xmlTextWriterEndDocument(writer);
|
||||||
|
|
||||||
xmlFreeTextWriter(writer);
|
xmlFreeTextWriter(writer);
|
||||||
ret_none:
|
ret_none:
|
||||||
return ret;
|
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);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user