Compare commits

...

25 Commits

Author SHA1 Message Date
29fdc841b7 Update cmake version 2025-05-10 22:53:35 +02:00
dc30188593 Update libraries 2025-05-10 22:51:36 +02:00
2bea5d288c Update linklist for cmake version 2025-05-10 22:47:55 +02:00
8a0226a5ea Fix typos in man page 2023-05-29 23:27:24 +02:00
ed6373473c Fix use of unitialized variable for nocolor terminal output 2023-05-29 23:13:06 +02:00
80b5f5b1b3 Fix error and debug messages in main.c 2023-05-29 23:07:03 +02:00
4fab6ffd3a Unify error messages in elfpatch.c 2023-05-29 23:06:02 +02:00
0ee19eaea4 Fix typo in man page 2023-05-29 23:04:00 +02:00
26eb480343 Add colors to error output and improve messages 2023-01-21 17:32:32 +01:00
30e47d533a Fix #4: Add support for endianess in struct output format 2023-01-20 19:51:25 +01:00
faeab33375 Allow for ELF files without program headers e.g. unlinked object files. 2023-01-20 19:39:54 +01:00
7e414f8576 Enhance verbose output of section table
* Add more section types to prevent "unknown" from printing
* Add alloc, exec, and write flags of sections to output table
2023-01-20 19:38:10 +01:00
933680c80d Use builtin byteswap functions to perform endianess conversion 2023-01-20 19:37:10 +01:00
891df1803e Add byteswap and endian destection code to elfpatch 2023-01-20 19:36:30 +01:00
7be1d6a967 Automatically add version to man page 2023-01-15 21:38:13 +01:00
e8a8abbe65 Remove debugging printfs 2023-01-15 21:26:19 +01:00
71b1ad2a32 Allow generation of reversed CRCs in main function. Reversed CRCs are now supported. 2023-01-15 21:23:31 +01:00
cf7d0c22f7 Add support for reversed CRCs in elfpatching 2023-01-15 21:21:00 +01:00
6f40e37e81 Add support for the reversed CRC algorithm to CRC module 2023-01-15 21:12:20 +01:00
84c60fc461 Add test output value to CRC list 2023-01-15 21:09:46 +01:00
b47828014e Fix style issues in elfpatch.c 2023-01-06 20:24:12 +01:00
2c7ce64722 Fix style issues in crc.c 2023-01-06 20:17:14 +01:00
dc85955859 Fix style issues in main.c 2023-01-06 20:15:44 +01:00
5ec8d8d90b Fix style issues in named_crcs.c 2023-01-06 20:09:55 +01:00
e33c48618b Fix style in xml.c 2023-01-06 20:07:52 +01:00
13 changed files with 351 additions and 141 deletions

2
3rdparty/libfort vendored

@ -1 +1 @@
Subproject commit 41237162a9bd34a30a88069ee4e230584ae8d674 Subproject commit 5a8f9312bdbe05be484d2c07dd8c94a39e0ae196

View File

@ -1,14 +1,14 @@
# Maintainer: Mario Hüttel <mario (dot) huettel (!) gmx (dot) net> # Maintainer: Mario Hüttel <mario (dot) huettel (!) gmx (dot) net>
pkgname=patchelfcrc pkgname=patchelfcrc
pkgver=5e7f697 pkgver=v1.0.0_rc1
pkgrel=1 pkgrel=1
pkgdesc="Tool for patching CRC checksums of sections into ELF binaries" pkgdesc="Tool for patching CRC checksums of sections into ELF binaries"
arch=('i686' 'x86_64') arch=('i686' 'x86_64')
url="https://git.shimatta.de/mhu/patchelfcrc" url="https://git.shimatta.de/mhu/patchelfcrc"
licence=('GPLv2') licence=('GPLv2')
depends=('libelf' 'libxml2') depends=('libelf' 'libxml2')
makedepends=('cmake' 'pandoc' 'git' 'gvim') makedepends=('cmake' 'pandoc' 'git' 'gvim' 'bash')
provides=('patchelfcrc') 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") 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') sha1sums=('SKIP' 'SKIP' 'SKIP')

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5...3.18)
project(patchelfcrc LANGUAGES C) project(patchelfcrc LANGUAGES C)

View File

@ -21,14 +21,25 @@
#include <stdbool.h> #include <stdbool.h>
#define print_err(fmt, ...) fprintf(stderr, "[ERR] " fmt, ## __VA_ARGS__) /**
* @brief Setting for reporting to console.
*/
enum reporting_color_mode {
COLOR_MODE_DETECT, /**< @brief Automatically detect if tty. If tty, color is used */
COLOR_MODE_COLOR, /**< @brief Force color mode on stderr */
COLOR_MODE_COLOR_OFF, /**< @brief Force no color on stderr */
};
#define print_warn(fmt, ...) fprintf(stderr, "[WARN] " fmt, ## __VA_ARGS__) void print_err(const char *fmt, ...);
void print_warn(const char *fmt, ...);
void print_debug(const char *fmt, ...); void print_debug(const char *fmt, ...);
void reporting_enable_verbose(void); void reporting_enable_verbose(bool state);
bool reporting_get_verbosity(void); bool reporting_get_verbosity(void);
void reporting_init(enum reporting_color_mode mode);
#endif /* _REPORTING_H_ */ #endif /* _REPORTING_H_ */

@ -1 +1 @@
Subproject commit c20b5c2528a46fe6a4aa74631ae3b628f73ac24f Subproject commit fdd99bad488bfd60cff152c0ec17bc927ed2e232

View File

@ -10,10 +10,10 @@ add_custom_command(
OUTPUT OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/${MAN_PAGE_NAME} ${CMAKE_CURRENT_BINARY_DIR}/${MAN_PAGE_NAME}
COMMAND COMMAND
bash -c "pandoc \"${CMAKE_CURRENT_SOURCE_DIR}/patchelfcrc.1.md\" -s -t man | gzip > \"${CMAKE_CURRENT_BINARY_DIR}/${MAN_PAGE_NAME}\"" bash -c "cat \"${CMAKE_CURRENT_SOURCE_DIR}/patchelfcrc.1.md\" | sed \"s/!version!/`git describe --tags --always --dirty`/\" | pandoc -s -t man | gzip > \"${CMAKE_CURRENT_BINARY_DIR}/${MAN_PAGE_NAME}\""
VERBATIM VERBATIM
WORKING_DIRECTORY WORKING_DIRECTORY
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
MAIN_DEPENDENCY MAIN_DEPENDENCY
${CMAKE_CURRENT_SOURCE_DIR}/patchelfcrc.1.md ${CMAKE_CURRENT_SOURCE_DIR}/patchelfcrc.1.md
) )

View File

@ -1,4 +1,4 @@
% patchelfcrc(1) 0.0.2 % patchelfcrc(1) !version!
% Mario Huettel % Mario Huettel
% October 2022 % October 2022
@ -61,7 +61,7 @@
: Export the calculated files to an XML file *XMLFILE*. : Export the calculated files to an XML file *XMLFILE*.
**--import**=*XMLFILE* **--import**=*XMLFILE*
: Import the CRCs from an XML file *XMLFILE* and do not caclulate anything in the given *ELF* : Import the CRCs from an XML file *XMLFILE* and do not calculate anything in the given *ELF*
**--help**, **-h**, **-?** **--help**, **-h**, **-?**
: Print help. : Print help.
@ -84,6 +84,9 @@
**--usage** **--usage**
: Print usage hints on command line options. : Print usage hints on command line options.
**--no-color**
: Force output on stdout and stderr to be pure text without color codes.
# EXAMPLES # EXAMPLES
**patchelfcrc** --list-crcs **patchelfcrc** --list-crcs
@ -131,9 +134,9 @@
**patchelfcrc** -l -g word --start-magic=0x12345678 --end-magic=0x8754321 -p crc-32-mpeg -f bare -O .outputsection -S .text executable.elf **patchelfcrc** -l -g word --start-magic=0x12345678 --end-magic=0x8754321 -p crc-32-mpeg -f bare -O .outputsection -S .text executable.elf
: Calculate the CRC over *.text* section and place the result in the *.outputsection* section. : Calculate the CRC over *.text* section and place the result in the *.outputsection* section.
The output sections start and end are checked for the given magic numbers in order to assure correct memory layout. The output sections start and end are checked for the given magic numbers in order to ensure correct memory layout.
*CRC-32-MPEG* is used as CRC algorothm. *CRC-32-MPEG* is used as CRC algorithm.
The memory is interpreted as *little endian* and the CRC calculation granularity is a 32 bit *word*. The memory is interpreted as *little endian* and the CRC calculation granularity is a 32 bit *word*.
# BUGS # BUGS
Currently, reversed CRC algorithms are not implemented. None

View File

@ -34,13 +34,26 @@ int crc_len_from_poly(uint64_t polynomial)
return pos; return pos;
} }
static uint32_t reverse_short_poly(uint32_t poly, uint8_t len)
{
uint8_t i;
uint32_t ret = 0ul;
for (i = 0; i < len; i++) {
ret <<= 1;
ret |= (poly & 1u);
poly >>= 1;
}
return ret;
}
static uint64_t shorten_polynomial(uint64_t poly) static uint64_t shorten_polynomial(uint64_t poly)
{ {
int i; int i;
for (i = 32; i >= 0; i--) {
for (i = 31; i <= 0; i--) { if (poly & ((uint64_t)1ull << i)) {
if (poly & (1 << i)) { poly &= ~((uint64_t)1ull<<i);
poly &= ~(1<<i);
break; break;
} }
} }
@ -55,14 +68,22 @@ static void internal_push_byte(struct crc_calc *crc, const uint8_t *data, size_t
crc_val = crc->crc_val; crc_val = crc->crc_val;
for (i = 0; i < len; i++, data++) { if (crc->settings.rev) {
crc_val = ((crc_val << 8) & crc->crc_mask) ^ crc->table[((crc_val >> (crc->crc_length-8u)) & 0xff) ^ *data]; for (i = 0; i < len; i++, data++) {
crc_val = (crc_val >> 8) ^ crc->table[((crc_val & 0xFF) ^ *data)];
}
} else {
/* Non reversed algo */
for (i = 0; i < len; i++, data++) {
crc_val = ((crc_val << 8) & crc->crc_mask) ^
crc->table[((crc_val >> (crc->crc_length-8u)) & 0xff) ^ *data];
}
} }
crc->crc_val = crc_val; crc->crc_val = crc_val;
} }
static void fill_crc_table(struct crc_calc *crc) static void fill_crc_table_non_reversed(struct crc_calc *crc)
{ {
uint32_t input; uint32_t input;
uint32_t crc_reg; uint32_t crc_reg;
@ -86,10 +107,44 @@ static void fill_crc_table(struct crc_calc *crc)
crc_reg <<= 1; crc_reg <<= 1;
} }
} }
crc->table[input] = crc_reg; crc->table[input] = crc_reg & crc->crc_mask;
} }
} }
static void fill_crc_table_reversed(struct crc_calc *crc)
{
uint32_t input;
uint32_t crc_reg;
uint32_t short_poly;
int i;
short_poly = (uint32_t)shorten_polynomial(crc->settings.polynomial);
short_poly = reverse_short_poly(short_poly, crc->crc_length);
for (input = 0; input <= 255u; input++) {
crc_reg = (uint32_t)input;
for (i = 0; i < 8; i++) {
/* Check LSB for reversed CRC shifting */
if (crc_reg & 1u) {
crc_reg >>= 1;
crc_reg ^= short_poly;
} else {
crc_reg >>= 1;
}
}
crc->table[input] = crc_reg & crc->crc_mask;
}
}
static void fill_crc_table(struct crc_calc *crc)
{
if (crc->settings.rev)
fill_crc_table_reversed(crc);
else
fill_crc_table_non_reversed(crc);
}
void crc_init(struct crc_calc *crc, const struct crc_settings *settings) void crc_init(struct crc_calc *crc, const struct crc_settings *settings)
{ {
uint32_t i; uint32_t i;

View File

@ -30,6 +30,19 @@
#include <fort.h> #include <fort.h>
#include <inttypes.h> #include <inttypes.h>
#include <patchelfcrc/crc-output-struct.h> #include <patchelfcrc/crc-output-struct.h>
#include <byteswap.h>
static const union {
uint8_t data[4];
uint32_t val;
} _endianess_check_union = {{1u, 2u, 3u, 4u}};
enum endianess {
END_LITTLE = 0x04030201ul,
END_BIG = 0x01020304ul,
};
#define HOST_ENDIANESS (_endianess_check_union.val)
struct elf_section { struct elf_section {
GElf_Shdr section_header; GElf_Shdr section_header;
@ -55,16 +68,16 @@ struct elfpatch {
#define is_elfpatch_struct(x) ((x) && (x)->magic == (ELFPATCH_MAGIC)) #define is_elfpatch_struct(x) ((x) && (x)->magic == (ELFPATCH_MAGIC))
#define ret_if_ep_err(ep) do { \ #define ret_if_ep_err(ep) do { \
if (!is_elfpatch_struct((ep))) { \ if (!is_elfpatch_struct((ep))) { \
return; \ return; \
} \ } \
} while(0) } while (0)
#define ret_val_if_ep_err(ep, val) do { \ #define ret_val_if_ep_err(ep, val) do { \
if (!is_elfpatch_struct((ep))) { \ if (!is_elfpatch_struct((ep))) { \
return (val); \ return val; \
} \ } \
} while(0) } while (0)
/** /**
* @brief Convert a series of 4 bytes into a uint32_t dpending on endianess * @brief Convert a series of 4 bytes into a uint32_t dpending on endianess
@ -77,15 +90,16 @@ static uint32_t get_uint32_from_byte_string(const uint8_t *data, bool little_end
uint32_t out = 0ul; uint32_t out = 0ul;
int i; int i;
/* Always shift in in big endian format */
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
if (little_endian)
out >>= 8u;
else
out <<= 8u; out <<= 8u;
out |= (uint32_t)data[i];
out |= (((uint32_t)data[i]) << (little_endian ? 24u : 0u));
} }
/* Swap bytes if little endian */
if (little_endian)
out = bswap_32(out);
return out; return out;
} }
@ -96,14 +110,12 @@ static void write_crc_to_byte_array(uint8_t *byte_array, uint32_t crc, uint8_t c
if (!byte_array) if (!byte_array)
return; return;
if (!little_endian)
crc = bswap_32(crc);
for (i = 0; i < crc_size_bytes; i++) { for (i = 0; i < crc_size_bytes; i++) {
if (little_endian) { byte_array[i] = (uint8_t)(crc & 0xFFul);
byte_array[i] = (uint8_t)(crc & 0xFFul); crc >>= 8u;
crc >>= 8u;
} else {
byte_array[i] = (uint8_t)((crc & 0xFF000000ul) >> 24u);
crc <<= 8u;
}
} }
} }
@ -136,6 +148,14 @@ static const char *section_type_to_str(Elf64_Word type)
return "INIT_ARRAY"; return "INIT_ARRAY";
case SHT_FINI_ARRAY: case SHT_FINI_ARRAY:
return "FINI_ARRAY"; return "FINI_ARRAY";
case SHT_PREINIT_ARRAY:
return "PREINIT_ARRAY";
case SHT_DYNAMIC:
return "DYNAMIC";
case SHT_ARM_ATTRIBUTES:
return "ARM_ATTRIBUTES";
case SHT_ARM_PREEMPTMAP:
return "ARM_PREEMPTMAP";
default: default:
break; break;
} }
@ -147,6 +167,7 @@ static void print_sections(elfpatch_handle_t *ep)
SlList *iter; SlList *iter;
ft_table_t *table; ft_table_t *table;
const struct elf_section *section; const struct elf_section *section;
bool alloc, write, exec;
ret_if_ep_err(ep); ret_if_ep_err(ep);
@ -162,15 +183,23 @@ static void print_sections(elfpatch_handle_t *ep)
/* Write header */ /* Write header */
ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER); ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);
ft_write_ln(table, "Section", "Type", "Size", "VMA", "LMA", "File Offset"); ft_write_ln(table, "Section", "Type", "ALLOC", "WRITE", "EXEC", "Size", "VMA", "LMA", "File Offset");
for (iter = ep->sections; iter; iter = sl_list_next(iter)) { for (iter = ep->sections; iter; iter = sl_list_next(iter)) {
section = (const struct elf_section *)iter->data; section = (const struct elf_section *)iter->data;
if (!section) if (!section)
continue; continue;
ft_printf_ln(table, "%s|%s|%lu|%p|%p|%p",
alloc = !!(section->section_header.sh_flags & SHF_ALLOC);
write = !!(section->section_header.sh_flags & SHF_WRITE);
exec = !!(section->section_header.sh_flags & SHF_EXECINSTR);
ft_printf_ln(table, "%s|%s|%s|%s|%s|%lu|%p|%p|%p",
section->name, section->name,
section_type_to_str(section->section_header.sh_type), section_type_to_str(section->section_header.sh_type),
alloc ? "x" : "",
write ? "x" : "",
exec ? "x" : "",
section->section_header.sh_size, section->section_header.sh_size,
(void *)section->section_header.sh_addr, (void *)section->section_header.sh_addr,
(void *)section->lma, (void *)section->lma,
@ -197,7 +226,7 @@ static SlList *elf_patch_get_sections(elfpatch_handle_t *ep)
sl_list_free_full(ret, (void (*)(void *))free_elf_section_element); sl_list_free_full(ret, (void (*)(void *))free_elf_section_element);
ep->sections = NULL; ep->sections = NULL;
if (elf_getshdrstrndx (ep->elf , &shstrndx) != 0) { if (elf_getshdrstrndx(ep->elf, &shstrndx) != 0) {
print_err("ELF error: %s\n", elf_errmsg(-1)); print_err("ELF error: %s\n", elf_errmsg(-1));
goto ret_free_section_list; goto ret_free_section_list;
} }
@ -218,9 +247,10 @@ static SlList *elf_patch_get_sections(elfpatch_handle_t *ep)
sec->lma = (uint64_t)sec->section_header.sh_addr; sec->lma = (uint64_t)sec->section_header.sh_addr;
name = elf_strptr(ep->elf, shstrndx, sec->section_header.sh_name); name = elf_strptr(ep->elf, shstrndx, sec->section_header.sh_name);
if (name) {
if (name)
sec->name = strdup(name); sec->name = strdup(name);
}
ret = sl_list_append(ret, sec); ret = sl_list_append(ret, sec);
} }
@ -260,6 +290,12 @@ static int elf_patch_read_program_headers(elfpatch_handle_t *ep)
return -1; return -1;
} }
if (header_count == 0) {
/* No program headers found. This ELF file is probably not linked */
ep->program_headers_count = 0;
return 0;
}
ep->program_headers = (GElf_Phdr *)malloc(header_count * sizeof(GElf_Phdr)); ep->program_headers = (GElf_Phdr *)malloc(header_count * sizeof(GElf_Phdr));
if (!ep->program_headers) { if (!ep->program_headers) {
/* Mem error. Abort. Program will crash eventually */ /* Mem error. Abort. Program will crash eventually */
@ -305,9 +341,11 @@ static void resolve_section_lmas(elfpatch_handle_t *ep)
if (!sec) if (!sec)
continue; continue;
/* By default each sections LMA is assumed to be its LMA as well */
sec->lma = (uint64_t)sec->section_header.sh_addr;
if (sec->section_header.sh_type == SHT_NOBITS) { if (sec->section_header.sh_type == SHT_NOBITS) {
/* Section does not contain data. It may be allocated but is not loaded. Therefore, LMA=VMA. */ /* 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; continue;
} }
@ -431,15 +469,13 @@ elfpatch_handle_t *elf_patch_open(const char *path, bool readonly, bool expect_l
switch (ident[5]) { switch (ident[5]) {
case 1: case 1:
print_debug("ELF Endianess: little\n"); print_debug("ELF Endianess: little\n");
if (!expect_little_endian) { if (!expect_little_endian)
print_err("Big endian format expected. File is little endian. Double check settings!\n"); print_warn("Big endian format expected. File is little endian. Double check settings!\n");
}
break; break;
case 2: case 2:
print_debug("ELF Endianess: big\n"); print_debug("ELF Endianess: big\n");
if (expect_little_endian) { if (expect_little_endian)
print_err("Little endian format expected. File is big endian. Double check settings!\n"); print_warn("Little endian format expected. File is big endian. Double check settings!\n");
}
break; break;
default: default:
print_err("Cannot determine endianess of ELF file. EI_DATA is: %d\n", ident[5]); print_err("Cannot determine endianess of ELF file. EI_DATA is: %d\n", ident[5]);
@ -454,9 +490,8 @@ close_elf:
ep->elf = NULL; ep->elf = NULL;
} }
close_fd: close_fd:
if (ep->fd > 0) { if (ep->fd > 0)
close(ep->fd); close(ep->fd);
}
free_struct: free_struct:
free(ep); free(ep);
ep = NULL; ep = NULL;
@ -491,14 +526,14 @@ int elf_patch_check_for_section(elfpatch_handle_t *ep, const char *section)
return ret; return ret;
} }
static size_t translate_index(size_t index, enum granularity granularity, bool little_endian) static size_t translate_index(size_t index, enum granularity granularity, bool little_endian, bool reversed)
{ {
size_t word_idx; size_t word_idx;
size_t part_idx; size_t part_idx;
size_t d_index; size_t d_index;
size_t gran_in_bytes; size_t gran_in_bytes;
if (!little_endian || granularity == GRANULARITY_BYTE) if ((!little_endian && !reversed) || (little_endian && reversed) || granularity == GRANULARITY_BYTE)
return index; return index;
gran_in_bytes = (size_t)granularity / 8u; gran_in_bytes = (size_t)granularity / 8u;
@ -526,30 +561,30 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio
/* Find section */ /* Find section */
sec = find_section_in_list(ep->sections, section); sec = find_section_in_list(ep->sections, section);
if (!sec) { if (!sec) {
print_err("Cannot find section %s\n", section); print_err("Cannot find section '%s'\n", section);
return -1; return -1;
} }
data = elf_getdata(sec->scn, NULL); data = elf_getdata(sec->scn, NULL);
if (!data) { if (!data) {
print_err("Error reading section data from %s: %s\n", section, elf_errmsg(-1)); print_err("Error reading section data from '%s': %s\n", section, elf_errmsg(-1));
return -1; return -1;
} }
print_debug("Section data length: %lu\n", data->d_size);
if (!data->d_size) { if (!data->d_size) {
print_err("Section %s contains no data.\n", section); print_err("Section '%s' contains no data.\n", section);
return -2; return -2;
} }
/* NOBIT sections have a length but no data in the file. Abort in this case */ /* NOBIT sections have a length but no data in the file. Abort in this case */
if (!data->d_buf) { if (!data->d_buf) {
print_err("Section %s does not contain loadable data.\n", section); print_err("Section '%s' does not contain loadable data.\n", section);
return -2; return -2;
} }
/* If big endian or granularity is byte, simply compute CRC. No reordering is necessary */ /* If big endian for non reversed / little endian for reversed or granularity is byte, simply compute CRC. No reordering is necessary */
if (!little_endian || granularity == GRANULARITY_BYTE) { if ((!little_endian && !crc->settings.rev) || (little_endian && crc->settings.rev) ||
granularity == GRANULARITY_BYTE) {
crc_push_bytes(crc, data->d_buf, data->d_size); crc_push_bytes(crc, data->d_buf, data->d_size);
} else { } else {
/* Little endian case with > byte sized chunks */ /* Little endian case with > byte sized chunks */
@ -557,18 +592,21 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio
/* Check granularity vs size of section */ /* Check granularity vs size of section */
padding_count = (gran_in_bytes - data->d_size % gran_in_bytes) % gran_in_bytes; padding_count = (gran_in_bytes - data->d_size % gran_in_bytes) % gran_in_bytes;
if (padding_count) { if (padding_count) {
print_err("Section '%s' is not a multiple size of the given granularity. %u zero padding bytes will be added.\n", print_warn("Section '%s' is not a multiple size of the given granularity. %u zero padding bytes will be added.\n",
section, padding_count); section, padding_count);
} }
for (idx = 0; idx < data->d_size; idx++) { for (idx = 0; idx < data->d_size; idx++)
crc_push_byte(crc, ((char *)data->d_buf)[translate_index(idx, granularity, little_endian)]); crc_push_byte(crc,
} ((char *)data->d_buf)[
translate_index(idx, granularity,
little_endian,
crc->settings.rev)
]);
/* Pad with zeroes */ /* Pad with zeroes */
for (idx = 0; idx < padding_count; idx++) { for (idx = 0; idx < padding_count; idx++)
crc_push_byte(crc, 0x00); crc_push_byte(crc, 0x00);
}
} }
return 0; return 0;
@ -594,7 +632,7 @@ static size_t calculate_needed_space_for_crcs(enum crc_format format,
break; break;
default: default:
needed_space = 0; needed_space = 0;
print_err("Unsupported CRC output format\n"); print_err("Unsupported CRC output format.\n");
} }
/* Add existing magic numbers to required space */ /* Add existing magic numbers to required space */
if (check_start_magic) { if (check_start_magic) {
@ -649,6 +687,7 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *output_se
struct crc_out_struct_32bit crc_32bit; struct crc_out_struct_32bit crc_32bit;
struct crc_out_struct_64bit crc_64bit; struct crc_out_struct_64bit crc_64bit;
uint64_t in_sec_addr, in_sec_len; uint64_t in_sec_addr, in_sec_len;
bool needs_byteswap;
ret_val_if_ep_err(ep, -1000); ret_val_if_ep_err(ep, -1000);
@ -711,8 +750,8 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *output_se
print_debug("Single CRC requires %u bytes.\n", (unsigned int)crc_size_bytes); print_debug("Single CRC requires %u bytes.\n", (unsigned int)crc_size_bytes);
needed_space = calculate_needed_space_for_crcs(format, crc_data->elf_bits, check_start_magic, check_end_magic, crc_size_bytes, needed_space = calculate_needed_space_for_crcs(format, crc_data->elf_bits, check_start_magic,
crc_count); 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, crc_count,
@ -746,6 +785,12 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *output_se
if (check_start_magic && crc_data->elf_bits == 64) if (check_start_magic && crc_data->elf_bits == 64)
sec_bytes += 4u; sec_bytes += 4u;
needs_byteswap = false;
if ((HOST_ENDIANESS != END_LITTLE && little_endian) ||
(HOST_ENDIANESS == END_LITTLE && !little_endian)) {
needs_byteswap = true;
}
for (iter = crc_data->crc_entries, idx = 0; iter; iter = sl_list_next(iter), idx++) { for (iter = crc_data->crc_entries, idx = 0; iter; iter = sl_list_next(iter), idx++) {
crc_entry = (struct crc_entry *)iter->data; crc_entry = (struct crc_entry *)iter->data;
in_sec_addr = use_vma ? crc_entry->vma : crc_entry->lma; in_sec_addr = use_vma ? crc_entry->vma : crc_entry->lma;
@ -756,18 +801,19 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *output_se
print_debug("Corresponding input section at 0x%"PRIx64", length: %"PRIu64"\n", print_debug("Corresponding input section at 0x%"PRIx64", length: %"PRIu64"\n",
in_sec_addr, in_sec_addr,
in_sec_len); in_sec_len);
if (crc_data->elf_bits == 32) { if (crc_data->elf_bits == 32) {
crc_32bit.crc = crc_entry->crc; crc_32bit.crc = needs_byteswap ? bswap_32(crc_entry->crc) : crc_entry->crc;
crc_32bit.length = (uint32_t)in_sec_len; crc_32bit.length = needs_byteswap ? bswap_32((uint32_t)in_sec_len) : (uint32_t)in_sec_len;
crc_32bit.start_address = (uint32_t)in_sec_addr; crc_32bit.start_address = needs_byteswap ? bswap_32((uint32_t)in_sec_addr) : (uint32_t)in_sec_addr;
memcpy(sec_bytes, &crc_32bit, sizeof(crc_32bit)); memcpy(sec_bytes, &crc_32bit, sizeof(crc_32bit));
sec_bytes += sizeof(crc_32bit); sec_bytes += sizeof(crc_32bit);
} else { } else {
/* 64 bit case */ /* 64 bit case */
crc_64bit.crc = crc_entry->crc; crc_64bit.crc = needs_byteswap ? bswap_32(crc_entry->crc) : crc_entry->crc;
crc_64bit._unused_dummy = 0ul; crc_64bit._unused_dummy = 0ul;
crc_64bit.length = in_sec_len; crc_64bit.length = needs_byteswap ? bswap_64(in_sec_len) : in_sec_len;
crc_64bit.start_address = in_sec_addr; crc_64bit.start_address = needs_byteswap ? bswap_64(in_sec_addr) : in_sec_addr;
memcpy(sec_bytes, &crc_64bit, sizeof(crc_64bit)); memcpy(sec_bytes, &crc_64bit, sizeof(crc_64bit));
sec_bytes += sizeof(crc_64bit); sec_bytes += sizeof(crc_64bit);
} }
@ -782,11 +828,10 @@ int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *output_se
crc_64bit.length = 0ull; crc_64bit.length = 0ull;
crc_64bit.start_address = 0ull; crc_64bit.start_address = 0ull;
if (crc_data->elf_bits == 32) { if (crc_data->elf_bits == 32)
memcpy(sec_bytes, &crc_32bit, sizeof(crc_32bit)); memcpy(sec_bytes, &crc_32bit, sizeof(crc_32bit));
} else { else
memcpy(sec_bytes, &crc_64bit, sizeof(crc_64bit)); memcpy(sec_bytes, &crc_64bit, sizeof(crc_64bit));
}
} }
/* Flag section data as invalid to trigger rewrite. /* Flag section data as invalid to trigger rewrite.
@ -808,9 +853,8 @@ void elf_patch_close_and_free(elfpatch_handle_t *ep)
if (ep->readonly) { if (ep->readonly) {
print_debug("DRY RUN: File will not be updated\n"); print_debug("DRY RUN: File will not be updated\n");
} else { } else {
if (elf_update(ep->elf, ELF_C_WRITE) < 0) { if (elf_update(ep->elf, ELF_C_WRITE) < 0)
print_err("Error writing ELF file: %s\n", elf_errmsg(-1)); print_err("Error writing ELF file: %s\n", elf_errmsg(-1));
}
} }
} }

View File

@ -40,8 +40,10 @@ const char *argp_program_bug_address = "<mario [dot] huettel [at] linux [dot] co
#define ARG_KEY_IMPORT (6) #define ARG_KEY_IMPORT (6)
#define ARG_KEY_USE_VMA (7) #define ARG_KEY_USE_VMA (7)
#define ARG_KEY_XSD (8) #define ARG_KEY_XSD (8)
#define ARG_KEY_FORCE_NO_COLOR (9)
struct command_line_options { struct command_line_options {
bool force_nocolor;
bool little_endian; bool little_endian;
bool dry_run; bool dry_run;
bool verbose; bool verbose;
@ -104,15 +106,18 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
case ARG_KEY_USE_VMA: case ARG_KEY_USE_VMA:
args->use_vma = true; args->use_vma = true;
break; break;
case ARG_KEY_FORCE_NO_COLOR:
args->force_nocolor = true;
break;
case 'p': case 'p':
/* Polyniomial */ /* Polyniomial */
args->crc.polynomial = strtoull(arg, &endptr, 0); args->crc.polynomial = strtoull(arg, &endptr, 0);
if (endptr == arg) { if (endptr == arg) {
if ((looked_up_crc = lookup_named_crc(arg))) { looked_up_crc = lookup_named_crc(arg);
if (looked_up_crc)
memcpy(&args->crc, &looked_up_crc->settings, sizeof(struct crc_settings)); memcpy(&args->crc, &looked_up_crc->settings, sizeof(struct crc_settings));
} else { else
argp_error(state, "Error parsing polynomial: %s\n", arg); argp_error(state, "Error parsing polynomial: %s\n", arg);
}
} }
break; break;
case 'l': case 'l':
@ -195,6 +200,7 @@ static int parse_cmdline_options(int *argc, char ***argv, struct command_line_op
{"import", ARG_KEY_IMPORT, "XML", 0, "Do not caclulate CRCs but import them from 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}, {"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}, {"use-vma", ARG_KEY_USE_VMA, 0, 0, "Use the VMA instead of the LMA for struct output", 2},
{"no-color", ARG_KEY_FORCE_NO_COLOR, 0, 0, "Force the output to be text only without colors", 0},
/* Sentinel */ /* Sentinel */
{NULL, 0, 0, 0, NULL, 0} {NULL, 0, 0, 0, NULL, 0}
}; };
@ -233,12 +239,11 @@ static void prepare_default_opts(struct command_line_options *opts)
opts->output_section = NULL; opts->output_section = NULL;
opts->export_xml = NULL; opts->export_xml = NULL;
opts->import_xml = NULL; opts->import_xml = NULL;
opts->force_nocolor = false;
} }
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)
{ {
int i;
SlList *list_iter;
const struct named_crc *predef_crc; const struct named_crc *predef_crc;
print_debug("Start CRC patching\n"); print_debug("Start CRC patching\n");
@ -261,28 +266,17 @@ static void print_verbose_start_info(const struct command_line_options *cmd_opts
print_debug("CRC length: %d\n", crc_len_from_poly(cmd_opts->crc.polynomial)); print_debug("CRC length: %d\n", crc_len_from_poly(cmd_opts->crc.polynomial));
} }
if (cmd_opts->elf_path) { if (cmd_opts->elf_path)
print_debug("ELF file: %s\n", cmd_opts->elf_path); print_debug("ELF file: %s\n", cmd_opts->elf_path);
}
if (cmd_opts->output_section) { if (cmd_opts->output_section)
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) { if (cmd_opts->export_xml)
print_debug("Export CRCs to '%s'\n", cmd_opts->export_xml); print_debug("Export CRCs to '%s'\n", cmd_opts->export_xml);
}
if (cmd_opts->import_xml) { if (cmd_opts->import_xml)
print_debug("Import CRCs from '%s'\n", 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);
}
}
} }
static void free_cmd_args(struct command_line_options *opts) static void free_cmd_args(struct command_line_options *opts)
@ -322,6 +316,7 @@ static int check_all_sections_present(elfpatch_handle_t *ep, SlList *list)
sec_name = (const char *)iter->data; sec_name = (const char *)iter->data;
if (!sec_name) if (!sec_name)
continue; continue;
if (elf_patch_check_for_section(ep, sec_name)) { if (elf_patch_check_for_section(ep, sec_name)) {
print_err("Cannot find section '%s'\n", sec_name); print_err("Cannot find section '%s'\n", sec_name);
ret = -2; ret = -2;
@ -340,7 +335,8 @@ static int check_all_sections_present(elfpatch_handle_t *ep, SlList *list)
* @param opts Command line options. Used for CRC generation * @param opts Command line options. Used for CRC generation
* @return CRC data * @return CRC data
*/ */
static struct crc_import_data *compute_crcs(elfpatch_handle_t *ep, SlList *list, const struct command_line_options *opts) static struct crc_import_data *compute_crcs(elfpatch_handle_t *ep, SlList *list,
const struct command_line_options *opts)
{ {
SlList *iter; SlList *iter;
const char *sec_name; const char *sec_name;
@ -423,13 +419,18 @@ int main(int argc, char **argv)
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) { if (cmd_opts.print_xsd) {
xml_print_xsd(); xml_print_xsd();
goto free_cmds; goto free_cmds;
} }
/* Initialize console output */
reporting_init(cmd_opts.force_nocolor ? COLOR_MODE_COLOR_OFF : COLOR_MODE_DETECT);
if (cmd_opts.verbose || cmd_opts.dry_run) if (cmd_opts.verbose || cmd_opts.dry_run)
reporting_enable_verbose(); reporting_enable_verbose(true);
print_verbose_start_info(&cmd_opts); print_verbose_start_info(&cmd_opts);
if (cmd_opts.list) { if (cmd_opts.list) {
@ -448,19 +449,11 @@ int main(int argc, char **argv)
return -2; return -2;
} }
if (cmd_opts.use_vma && cmd_opts.format != FORMAT_STRUCT) { if (cmd_opts.use_vma && cmd_opts.format != FORMAT_STRUCT)
print_warn("--use-vma option only has an effect when exporting as struct output.\n"); 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) { 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"); print_warn("No output section or XML export specified. Will continue but not create any output.\n");
}
/* Do error printing if using a reversed polynomial. It is not implemented yet! */
if (cmd_opts.crc.rev) {
print_err("Reversed polynomials are not supported yet\nExiting...\n");
goto free_cmds;
}
/* Prepare libelf for use with the latest ELF version */ /* Prepare libelf for use with the latest ELF version */
elf_version(EV_CURRENT); elf_version(EV_CURRENT);
@ -481,13 +474,11 @@ int main(int argc, char **argv)
/* Compute CRCs over sections */ /* Compute CRCs over sections */
crc_data = compute_crcs(ep, cmd_opts.section_list, &cmd_opts); crc_data = compute_crcs(ep, cmd_opts.section_list, &cmd_opts);
if (!crc_data) { if (!crc_data)
goto ret_close_elf; goto ret_close_elf;
}
if (reporting_get_verbosity()) { if (reporting_get_verbosity())
print_crcs(crc_data); print_crcs(crc_data);
}
} else { } else {
crc_data = xml_import_from_file(cmd_opts.import_xml); crc_data = xml_import_from_file(cmd_opts.import_xml);
} }
@ -504,7 +495,7 @@ int main(int argc, char **argv)
if (cmd_opts.export_xml) { if (cmd_opts.export_xml) {
if (xml_write_crcs_to_file(cmd_opts.export_xml, crc_data)) { if (xml_write_crcs_to_file(cmd_opts.export_xml, crc_data)) {
print_err("Error during XML generation\n"); print_err("Error during XML generation.\n");
ret = -3; ret = -3;
} }
} }

View File

@ -28,7 +28,7 @@
.xor = outxor, \ .xor = outxor, \
.start_value = init, \ .start_value = init, \
.rev = reverse \ .rev = reverse \
}} } }
const struct named_crc predefined_crc_table[] = { const struct named_crc predefined_crc_table[] = {
NAMED_CRC("crc-8", 0x107, false, 0x00, 0x00), NAMED_CRC("crc-8", 0x107, false, 0x00, 0x00),
@ -70,7 +70,7 @@ const struct named_crc predefined_crc_table[] = {
NAMED_CRC("jamcrc", 0x104C11DB7, true, 0xFFFFFFFF, 0x00000000), NAMED_CRC("jamcrc", 0x104C11DB7, true, 0xFFFFFFFF, 0x00000000),
NAMED_CRC("xfer", 0x1000000AF, false, 0x00000000, 0x00000000), NAMED_CRC("xfer", 0x1000000AF, false, 0x00000000, 0x00000000),
/* SENTINEL */ /* SENTINEL */
{.name = NULL, .settings = {0, 0, 0, false}}, { .name = NULL, .settings = {0, 0, 0, false} },
}; };
const struct named_crc *reverse_lookup_named_crc(const struct crc_settings *settings) const struct named_crc *reverse_lookup_named_crc(const struct crc_settings *settings)
@ -110,19 +110,26 @@ void list_predefined_crcs(void)
{ {
ft_table_t *table; ft_table_t *table;
const struct named_crc *iter; const struct named_crc *iter;
struct crc_calc crc;
table = ft_create_table(); table = ft_create_table();
ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER); ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);
ft_write_ln(table, "Name", "Polynomial", "Reversed", "Start Value", "Output XOR"); ft_write_ln(table, "Name", "Polynomial", "Reversed", "Start Value", "Output XOR", "Test Value");
for (iter = predefined_crc_table; iter->name; iter++) { for (iter = predefined_crc_table; iter->name; iter++) {
ft_printf_ln(table, "%s|0x%lx|%s|0x%x|0x%x", crc_init(&crc, &iter->settings);
/* Calculate the test value */
crc_push_bytes(&crc, (const uint8_t *)"123456789", 9);
crc_finish_calc(&crc);
ft_printf_ln(table, "%s|0x%lx|%s|0x%x|0x%x|0x%x",
iter->name, iter->name,
iter->settings.polynomial, iter->settings.polynomial,
iter->settings.rev ? "yes" : "no", iter->settings.rev ? "yes" : "no",
iter->settings.start_value, iter->settings.start_value,
iter->settings.xor); iter->settings.xor,
crc_get_value(&crc));
crc_destroy(&crc);
} }
printf("%s\n", ft_to_string(table)); printf("%s\n", ft_to_string(table));

View File

@ -19,9 +19,66 @@
#include <patchelfcrc/reporting.h> #include <patchelfcrc/reporting.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h>
#include <unistd.h>
static bool global_verbosity_state = false; static bool global_verbosity_state = false;
static bool reporting_use_color = false;
#define COLOR_RESET "\e[0m"
#define COLOR_BOLD_RED "\e[31;1m"
#define COLOR_RED "\e[31m"
#define COLOR_BOLD_YELLOW "\e[33;1m"
#define COLOR_YELLOW "\e[33m"
void print_err(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
/* Set color */
if (reporting_use_color)
fprintf(stderr, COLOR_BOLD_RED "[ERR]" COLOR_RESET " " COLOR_RED);
else
fprintf(stderr, "[ERR] ");
vfprintf(stderr, fmt, va);
/* Reset color */
if (reporting_use_color) {
fprintf(stderr, COLOR_RESET);
}
va_end(va);
}
void print_warn(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
/* Set color */
if (reporting_use_color)
fprintf(stderr, COLOR_BOLD_YELLOW "[WARN]" COLOR_RESET " " COLOR_YELLOW);
else
fprintf(stderr, "[WARN] ");
vfprintf(stderr, fmt, va);
/* Reset color */
if (reporting_use_color) {
fprintf(stderr, COLOR_RESET);
}
va_end(va);
}
void print_debug(const char *fmt, ...) void print_debug(const char *fmt, ...)
{ {
@ -34,12 +91,52 @@ void print_debug(const char *fmt, ...)
} }
} }
void reporting_enable_verbose(void) void reporting_enable_verbose(bool state)
{ {
global_verbosity_state = true; global_verbosity_state = state;
} }
bool reporting_get_verbosity(void) bool reporting_get_verbosity(void)
{ {
return global_verbosity_state; return global_verbosity_state;
} }
/**
* @brief Check whether stderr supports colors.
* @note This function checks for a tty and the TERM environment variable. It has to contain "xterm".
* @return true if colors are supported
* @return false if no colors should be used
*/
static bool stderr_supports_colors(void)
{
const char *env_var;
const char *tmp;
if (isatty(2) != 1)
return false;
env_var = getenv("TERM");
if (!env_var)
return false;
tmp = strstr(env_var, "xterm");
if (!tmp)
return false;
return true;
}
void reporting_init(enum reporting_color_mode mode)
{
switch (mode) {
case COLOR_MODE_COLOR:
reporting_use_color = true;
break;
case COLOR_MODE_COLOR_OFF:
reporting_use_color = false;
break;
default: /* Auto detect case and invalid settings */
reporting_use_color = stderr_supports_colors();
break;
}
}

View File

@ -30,9 +30,8 @@ int xml_write_crcs_to_file(const char *path, const struct crc_import_data *crc_d
const struct crc_entry *entry; const struct crc_entry *entry;
size_t index; size_t index;
if (!path || !crc_data) { if (!path || !crc_data)
return -1000; return -1000;
}
writer = xmlNewTextWriterFilename(path, 0); writer = xmlNewTextWriterFilename(path, 0);
if (!writer) { if (!writer) {
@ -67,7 +66,9 @@ int xml_write_crcs_to_file(const char *path, const struct crc_import_data *crc_d
xmlTextWriterStartElement(writer, BAD_CAST "sections"); xmlTextWriterStartElement(writer, BAD_CAST "sections");
/* Output all section CRCs */ /* Output all section CRCs */
for (entry_iter = crc_data->crc_entries, index = 0u; entry_iter; entry_iter = sl_list_next(entry_iter), index++) { 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; entry = (const struct crc_entry *)entry_iter->data;
xmlTextWriterStartElement(writer, BAD_CAST "crc"); xmlTextWriterStartElement(writer, BAD_CAST "crc");
xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "name", "%s", entry->name); xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "name", "%s", entry->name);
@ -222,7 +223,8 @@ static int convert_number_string_to_uint(const char *data, uint64_t *output)
* @return 0 if successful * @return 0 if successful
* @return negative in case of an error * @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) static int get_uint64_from_xpath_content(const char *xpath, xmlXPathContextPtr xpath_ctx,
uint64_t *output, bool required)
{ {
const char *data; const char *data;
int ret = -1; int ret = -1;
@ -245,7 +247,8 @@ static int get_uint64_from_xpath_content(const char *xpath, xmlXPathContextPtr x
* @return 0 if successful * @return 0 if successful
* @return negative in case of an error * @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) static int get_uint32_from_xpath_content(const char *xpath, xmlXPathContextPtr xpath_ctx,
uint32_t *output, bool required)
{ {
const char *data; const char *data;
uint64_t tmp; uint64_t tmp;
@ -359,10 +362,10 @@ struct crc_import_data *xml_import_from_file(const char *path)
print_err("Error reading XML file: %s\n", path); print_err("Error reading XML file: %s\n", path);
goto ret_none; goto ret_none;
} }
root_node = xmlDocGetRootElement(doc); root_node = xmlDocGetRootElement(doc);
if (!root_node) { if (!root_node)
goto ret_close_doc; goto ret_close_doc;
}
/* Validate the document */ /* Validate the document */
if (!validate_xml_doc(doc)) { if (!validate_xml_doc(doc)) {
@ -372,9 +375,8 @@ struct crc_import_data *xml_import_from_file(const char *path)
/* Get xpath context */ /* Get xpath context */
xpath_ctx = xmlXPathNewContext(doc); xpath_ctx = xmlXPathNewContext(doc);
if (!xpath_ctx) { if (!xpath_ctx)
goto ret_close_doc; goto ret_close_doc;
}
/* Get the version number and print error in case of incompatibility. Continue either way */ /* Get the version number and print error in case of incompatibility. Continue either way */
cptr = (char *)xmlGetProp(root_node, BAD_CAST "version"); cptr = (char *)xmlGetProp(root_node, BAD_CAST "version");