Compare commits
1 Commits
b3827b25c6
...
v0.0.5
Author | SHA1 | Date | |
---|---|---|---|
f4f373d65d |
@@ -26,7 +26,6 @@ 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)
|
||||||
|
|
||||||
@@ -40,33 +39,21 @@ 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 "")
|
||||||
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} ${LIBXML2_LIBRARIES} fort linklist-lib)
|
target_link_libraries(${PROJECT_NAME} ${ELF_LIBRARIES} fort linklist-lib)
|
||||||
target_link_directories(${PROJECT_NAME} PRIVATE ${ELF_LIBRARY_DIRS} ${LIBXML2_LIBRARY_DIRS})
|
target_link_directories(${PROJECT_NAME} PRIVATE ${ELF_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")
|
||||||
add_dependencies(${PROJECT_NAME} version-header schema-header)
|
add_dependencies(${PROJECT_NAME} version-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")
|
||||||
|
@@ -41,7 +41,7 @@ enum crc_format {
|
|||||||
FORMAT_STRUCT,
|
FORMAT_STRUCT,
|
||||||
};
|
};
|
||||||
|
|
||||||
elfpatch_handle_t *elf_patch_open(const char *path, bool readonly);
|
elfpatch_handle_t *elf_patch_open(const char *path, bool readonly, bool expect_little_endian);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if a section is present in file
|
* @brief Check if a section is present in file
|
||||||
@@ -50,27 +50,6 @@ 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
|
|
||||||
* @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
|
||||||
|
@@ -1,45 +0,0 @@
|
|||||||
#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>
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Print XML XSD file to stdout
|
|
||||||
*/
|
|
||||||
void xml_print_xsd(void);
|
|
||||||
|
|
||||||
#endif /* _ELFPATCHCRC_XML_H_ */
|
|
@@ -8,7 +8,7 @@
|
|||||||
# SYNOPSYS
|
# SYNOPSYS
|
||||||
**patchelfcrc** [**-lrv?V**] [**-g** *GRANULARITY*] [**-p** *POLYNOMIAL*] [**-s** *STARTVALUE*]
|
**patchelfcrc** [**-lrv?V**] [**-g** *GRANULARITY*] [**-p** *POLYNOMIAL*] [**-s** *STARTVALUE*]
|
||||||
[**-x** *XORVAL*] [**-F** *FORMAT*] [**-O** *OUTPUTSECTION*] [**-S** *SEC*]
|
[**-x** *XORVAL*] [**-F** *FORMAT*] [**-O** *OUTPUTSECTION*] [**-S** *SEC*]
|
||||||
[**\--granularity**=*GRANULARITY*] [**\--little-endian**] [**\--dry-run**] [**\--xsd**]
|
[**\--granularity**=*GRANULARITY*] [**\--little-endian**] [**\--dry-run**]
|
||||||
[**\--poly**=*POLYNOMIAL*] [**\--reversed**] [**\--start-value**=*STARTVALUE*]
|
[**\--poly**=*POLYNOMIAL*] [**\--reversed**] [**\--start-value**=*STARTVALUE*]
|
||||||
[**--verbose**] [**\--xor-out**=*XORVAL*] [**\--end-magic**=*MAGIC*]
|
[**--verbose**] [**\--xor-out**=*XORVAL*] [**\--end-magic**=*MAGIC*]
|
||||||
[**\--crc-format**=*FORMAT*] [**\--list-crcs**] [**\--output-section**=*OUTPUTSECTION*]
|
[**\--crc-format**=*FORMAT*] [**\--list-crcs**] [**\--output-section**=*OUTPUTSECTION*]
|
||||||
@@ -65,12 +65,6 @@
|
|||||||
**-V**, **\--version**
|
**-V**, **\--version**
|
||||||
: Print version number
|
: Print version number
|
||||||
|
|
||||||
**\--list-crcs**
|
|
||||||
: List the possible predefined CRCs
|
|
||||||
|
|
||||||
**\--xsd**
|
|
||||||
: Print the XSD file used to validate the XML import to stdout
|
|
||||||
|
|
||||||
**--usage**
|
**--usage**
|
||||||
: Print usage hints on command line options.
|
: Print usage hints on command line options.
|
||||||
|
|
||||||
|
@@ -1,67 +0,0 @@
|
|||||||
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
|
||||||
<xs:simpleType name="dec_hex_num">
|
|
||||||
<xs:restriction base="xs:string">
|
|
||||||
<xs:pattern value="([0-9]+|0x[0-9a-fA-F]+)"></xs:pattern>
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
<xs:simpleType name="elfclass_type">
|
|
||||||
<xs:union>
|
|
||||||
<xs:simpleType>
|
|
||||||
<xs:restriction base="xs:integer">
|
|
||||||
<xs:minInclusive value="32"/>
|
|
||||||
<xs:maxInclusive value="32"/>
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
<xs:simpleType>
|
|
||||||
<xs:restriction base="xs:integer">
|
|
||||||
<xs:minInclusive value="64"/>
|
|
||||||
<xs:maxInclusive value="64"/>
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
<xs:simpleType>
|
|
||||||
<!-- This is in case something unsupported is encountered -->
|
|
||||||
<xs:restriction base="xs:integer">
|
|
||||||
<xs:minInclusive value="-1"/>
|
|
||||||
<xs:maxInclusive value="-1"/>
|
|
||||||
</xs:restriction>
|
|
||||||
</xs:simpleType>
|
|
||||||
</xs:union>
|
|
||||||
</xs:simpleType>
|
|
||||||
<xs:element name="patchelfcrc">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element name="settings">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element type="dec_hex_num" name="poly"/>
|
|
||||||
<xs:element type="dec_hex_num" name="start"/>
|
|
||||||
<xs:element type="xs:string" fixed="" name="rev" minOccurs="0" maxOccurs="1"/>
|
|
||||||
<xs:element type="dec_hex_num" name="xor"/>
|
|
||||||
<xs:element type="elfclass_type" name="elfclass"/>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
<xs:element name="sections">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:choice minOccurs="1" maxOccurs="unbounded">
|
|
||||||
<xs:element name="crc">
|
|
||||||
<xs:complexType>
|
|
||||||
<xs:simpleContent>
|
|
||||||
<xs:extension base="dec_hex_num">
|
|
||||||
<xs:attribute type="xs:string" name="name"/>
|
|
||||||
<xs:attribute type="dec_hex_num" name="index"/>
|
|
||||||
<xs:attribute type="dec_hex_num" name="vma"/>
|
|
||||||
<xs:attribute type="dec_hex_num" name="size"/>
|
|
||||||
</xs:extension>
|
|
||||||
</xs:simpleContent>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
</xs:choice>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
</xs:sequence>
|
|
||||||
<xs:attribute type="xs:string" name="version"/>
|
|
||||||
</xs:complexType>
|
|
||||||
</xs:element>
|
|
||||||
</xs:schema>
|
|
||||||
|
|
@@ -293,9 +293,10 @@ static int elf_patch_update_info(elfpatch_handle_t *ep)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
elfpatch_handle_t *elf_patch_open(const char *path, bool readonly)
|
elfpatch_handle_t *elf_patch_open(const char *path, bool readonly, bool expect_little_endian)
|
||||||
{
|
{
|
||||||
struct elfpatch *ep;
|
struct elfpatch *ep;
|
||||||
|
const char *ident;
|
||||||
|
|
||||||
/* This is important to guarantee structure packing behavior */
|
/* This is important to guarantee structure packing behavior */
|
||||||
CRC_OUT_CHECK_STRUCT_SIZES;
|
CRC_OUT_CHECK_STRUCT_SIZES;
|
||||||
@@ -320,7 +321,7 @@ elfpatch_handle_t *elf_patch_open(const char *path, bool readonly)
|
|||||||
goto close_fd;
|
goto close_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prewvent Libelf from relayouting the sections, which would brick the load segments */
|
/* Prevent Libelf from relayouting the sections, which would brick the load segments */
|
||||||
elf_flagelf(ep->elf, ELF_C_SET, ELF_F_LAYOUT);
|
elf_flagelf(ep->elf, ELF_C_SET, ELF_F_LAYOUT);
|
||||||
|
|
||||||
if (elf_patch_update_info(ep)) {
|
if (elf_patch_update_info(ep)) {
|
||||||
@@ -328,6 +329,27 @@ elfpatch_handle_t *elf_patch_open(const char *path, bool readonly)
|
|||||||
goto close_elf;
|
goto close_elf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ident = elf_getident(ep->elf, NULL);
|
||||||
|
if (ident) {
|
||||||
|
switch (ident[5]) {
|
||||||
|
case 1:
|
||||||
|
print_debug("ELF Endianess: little\n");
|
||||||
|
if (!expect_little_endian) {
|
||||||
|
print_err("Big endian format expected. File is little endian. Double check settings!\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
print_debug("ELF Endianess: big\n");
|
||||||
|
if (expect_little_endian) {
|
||||||
|
print_err("Little endian format expected. File is big endian. Double check settings!\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print_err("Cannot determine endianess of ELF file. EI_DATA is: %d\n", ident[5]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (elfpatch_handle_t *)ep;
|
return (elfpatch_handle_t *)ep;
|
||||||
close_elf:
|
close_elf:
|
||||||
if (ep->elf) {
|
if (ep->elf) {
|
||||||
@@ -482,17 +504,6 @@ 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)
|
||||||
@@ -645,7 +656,7 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Flag section data as invalid to trigger rewrite.
|
/* Flag section data as invalid to trigger rewrite.
|
||||||
* This is needed to to the forced memory layout
|
* This is needed due to the forced memory layout
|
||||||
*/
|
*/
|
||||||
elf_flagdata(output_sec_data, ELF_C_SET, ELF_F_DIRTY);
|
elf_flagdata(output_sec_data, ELF_C_SET, ELF_F_DIRTY);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@@ -684,42 +695,3 @@ 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
65
src/main.c
65
src/main.c
@@ -27,7 +27,6 @@
|
|||||||
#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>";
|
||||||
@@ -36,15 +35,11 @@ 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)
|
|
||||||
#define ARG_KEY_XSD (7)
|
|
||||||
|
|
||||||
struct command_line_options {
|
struct command_line_options {
|
||||||
bool little_endian;
|
bool little_endian;
|
||||||
bool dry_run;
|
bool dry_run;
|
||||||
bool verbose;
|
bool verbose;
|
||||||
bool print_xsd;
|
|
||||||
enum granularity granularity;
|
enum granularity granularity;
|
||||||
enum crc_format format;
|
enum crc_format format;
|
||||||
struct crc_settings crc;
|
struct crc_settings crc;
|
||||||
@@ -56,8 +51,6 @@ 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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -87,18 +80,9 @@ 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;
|
||||||
case ARG_KEY_XSD:
|
|
||||||
args->print_xsd = true;
|
|
||||||
break;
|
|
||||||
case 'p':
|
case 'p':
|
||||||
/* Polyniomial */
|
/* Polyniomial */
|
||||||
args->crc.polynomial = strtoull(arg, &endptr, 0);
|
args->crc.polynomial = strtoull(arg, &endptr, 0);
|
||||||
@@ -160,6 +144,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,10 +170,7 @@ static int parse_cmdline_options(int *argc, char ***argv, struct command_line_op
|
|||||||
{"crc-format", 'F', "FORMAT", 0, "Output Format for CRCs.", 2},
|
{"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},
|
{"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},
|
|
||||||
{"xsd", ARG_KEY_XSD, 0, 0, "Print XSD to stdout", 0},
|
|
||||||
/* Sentinel */
|
/* Sentinel */
|
||||||
{NULL, 0, 0, 0, NULL, 0}
|
{NULL, 0, 0, 0, NULL, 0}
|
||||||
};
|
};
|
||||||
@@ -210,7 +192,6 @@ static void prepare_default_opts(struct command_line_options *opts)
|
|||||||
{
|
{
|
||||||
opts->little_endian = false;
|
opts->little_endian = false;
|
||||||
opts->verbose = false;
|
opts->verbose = false;
|
||||||
opts->print_xsd = false;
|
|
||||||
opts->granularity = GRANULARITY_BYTE;
|
opts->granularity = GRANULARITY_BYTE;
|
||||||
opts->dry_run = false;
|
opts->dry_run = false;
|
||||||
opts->crc.xor = 0UL;
|
opts->crc.xor = 0UL;
|
||||||
@@ -224,8 +205,6 @@ 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)
|
||||||
@@ -262,14 +241,6 @@ 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);
|
||||||
@@ -358,7 +329,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,14 +366,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);
|
||||||
if (cmd_opts.print_xsd) {
|
|
||||||
xml_print_xsd();
|
|
||||||
goto free_cmds;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd_opts.verbose || cmd_opts.dry_run)
|
if (cmd_opts.verbose || cmd_opts.dry_run)
|
||||||
reporting_enable_verbose();
|
reporting_enable_verbose();
|
||||||
@@ -420,13 +384,8 @@ int main(int argc, char **argv)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd_opts.export_xml && cmd_opts.import_xml) {
|
if (!cmd_opts.output_section) {
|
||||||
print_err("XML export and input cannot be specified at the same time.");
|
print_err("No output section specified. Will continue but not patch file.\n");
|
||||||
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! */
|
||||||
@@ -439,7 +398,7 @@ int main(int argc, char **argv)
|
|||||||
elf_version(EV_CURRENT);
|
elf_version(EV_CURRENT);
|
||||||
|
|
||||||
/* Open the ELF file */
|
/* Open the ELF file */
|
||||||
ep = elf_patch_open(cmd_opts.elf_path, cmd_opts.dry_run);
|
ep = elf_patch_open(cmd_opts.elf_path, cmd_opts.dry_run, cmd_opts.little_endian);
|
||||||
if (!ep) {
|
if (!ep) {
|
||||||
ret = -2;
|
ret = -2;
|
||||||
goto free_cmds;
|
goto free_cmds;
|
||||||
@@ -461,27 +420,15 @@ 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, crc_len_from_poly(cmd_opts.crc.polynomial),
|
crcs, 32, cmd_opts.start_magic, cmd_opts.end_magic,
|
||||||
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) {
|
|
||||||
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(crcs);
|
|
||||||
free_cmds:
|
free_cmds:
|
||||||
|
|
||||||
free_cmd_args(&cmd_opts);
|
free_cmd_args(&cmd_opts);
|
||||||
|
237
src/xml.c
237
src/xml.c
@@ -1,237 +0,0 @@
|
|||||||
#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 <libxml/xmlreader.h>
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <patchelfcrc/reporting.h>
|
|
||||||
#include <patchelfcrc/xml.h>
|
|
||||||
#include <patchelfcrc/version.h>
|
|
||||||
#include <generated/schema-blob.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;
|
|
||||||
int bitsize;
|
|
||||||
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);
|
|
||||||
/* 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);
|
|
||||||
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) {
|
|
||||||
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");
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
ret |= -1;
|
|
||||||
}
|
|
||||||
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 */
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void xml_print_xsd(void)
|
|
||||||
{
|
|
||||||
printf("%.*s", schema_xsd_len, schema_xsd);
|
|
||||||
}
|
|
Reference in New Issue
Block a user