Move source code to SRC folder and start doxygen
This commit is contained in:
152
src/crc.c
Normal file
152
src/crc.c
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* This file is part of patchelfcrc.
|
||||
* Copyright (c) 2022 Mario Hüttel.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 only.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <patchelfcrc/crc.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int crc_len_from_poly(uint64_t polynomial)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
/* Extract the MSB from the polynomial */
|
||||
for (pos = 63; pos >= 0; pos--) {
|
||||
if (polynomial & (((uint64_t)1ULL) << pos)) {
|
||||
/* Highest bit found */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static uint64_t shorten_polynomial(uint64_t poly)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 31; i <= 0; i--) {
|
||||
if (poly & (1 << i)) {
|
||||
poly &= ~(1<<i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return poly;
|
||||
}
|
||||
|
||||
static void internal_push_byte(struct crc_calc *crc, const uint8_t *data, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
uint32_t crc_val;
|
||||
|
||||
crc_val = crc->crc_val;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void fill_crc_table(struct crc_calc *crc)
|
||||
{
|
||||
uint32_t input;
|
||||
uint32_t crc_reg;
|
||||
uint32_t short_poly;
|
||||
uint32_t crc_len;
|
||||
int i;
|
||||
|
||||
crc_len = crc->crc_length;
|
||||
short_poly = (uint32_t)shorten_polynomial(crc->settings.polynomial);
|
||||
|
||||
for (input = 0; input <= 255u; input++) {
|
||||
|
||||
crc_reg = ((uint8_t)input) << (crc_len - 8u);
|
||||
|
||||
for (i = 7; i >= 0; i--) {
|
||||
|
||||
if (crc_reg & (1ul << (crc_len-1))) {
|
||||
crc_reg <<= 1;
|
||||
crc_reg ^= short_poly;
|
||||
} else {
|
||||
crc_reg <<= 1;
|
||||
}
|
||||
}
|
||||
crc->table[input] = crc_reg;
|
||||
}
|
||||
}
|
||||
|
||||
void crc_init(struct crc_calc *crc, const struct crc_settings *settings)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (!crc || !settings)
|
||||
return;
|
||||
|
||||
memcpy(&crc->settings, settings, sizeof(struct crc_settings));
|
||||
|
||||
crc->table = (uint32_t *)malloc(256 * sizeof(uint32_t));
|
||||
crc->crc_length = crc_len_from_poly(crc->settings.polynomial);
|
||||
|
||||
crc_reset(crc);
|
||||
|
||||
crc->crc_mask = 0x0UL;
|
||||
for (i = 0; i < crc->crc_length; i++)
|
||||
crc->crc_mask |= (1ul << i);
|
||||
|
||||
/* Initialize the table */
|
||||
fill_crc_table(crc);
|
||||
}
|
||||
|
||||
void crc_reset(struct crc_calc *crc)
|
||||
{
|
||||
crc->crc_val = crc->settings.start_value ^ crc->settings.xor;
|
||||
}
|
||||
|
||||
void crc_push_bytes(struct crc_calc *crc, const uint8_t *b, size_t len)
|
||||
{
|
||||
if (!crc)
|
||||
return;
|
||||
|
||||
internal_push_byte(crc, b, len);
|
||||
}
|
||||
|
||||
void crc_push_byte(struct crc_calc *crc, uint8_t b)
|
||||
{
|
||||
if (!crc)
|
||||
return;
|
||||
|
||||
internal_push_byte(crc, &b, 1ul);
|
||||
}
|
||||
|
||||
void crc_destroy(struct crc_calc *crc)
|
||||
{
|
||||
if (!crc)
|
||||
return;
|
||||
if (crc->table)
|
||||
free(crc->table);
|
||||
}
|
||||
|
||||
uint32_t crc_get_value(struct crc_calc *crc)
|
||||
{
|
||||
return crc->crc_val;
|
||||
}
|
||||
|
||||
void crc_finish_calc(struct crc_calc *crc)
|
||||
{
|
||||
crc->crc_val ^= crc->settings.xor;
|
||||
}
|
634
src/elfpatch.c
Normal file
634
src/elfpatch.c
Normal file
@@ -0,0 +1,634 @@
|
||||
#include <patchelfcrc/elfpatch.h>
|
||||
#include <patchelfcrc/reporting.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <libelf.h>
|
||||
#include <gelf.h>
|
||||
#include <linklist-lib/singly-linked-list.h>
|
||||
#include <fort.h>
|
||||
#include <inttypes.h>
|
||||
#include <patchelfcrc/crc-output-struct.h>
|
||||
|
||||
struct elf_section {
|
||||
GElf_Shdr section_header;
|
||||
Elf_Scn *scn;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct elfpatch {
|
||||
uint32_t magic;
|
||||
int fd;
|
||||
bool readonly;
|
||||
Elf *elf;
|
||||
GElf_Ehdr ehdr;
|
||||
int class;
|
||||
SlList *sections;
|
||||
};
|
||||
|
||||
#define ELFPATCH_MAGIC 0x8545637Aul
|
||||
|
||||
#define is_elfpatch_struct(x) ((x) && (x)->magic == (ELFPATCH_MAGIC))
|
||||
|
||||
#define ret_if_ep_err(ep) do { \
|
||||
if (!is_elfpatch_struct((ep))) { \
|
||||
return; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define ret_val_if_ep_err(ep, val) do { \
|
||||
if (!is_elfpatch_struct((ep))) { \
|
||||
return (val); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* @brief Convert a series of 4 bytes into a uint32_t dpending on endianess
|
||||
* @param data 4 bytes
|
||||
* @param little_endian data is little endian
|
||||
* @return uint32
|
||||
*/
|
||||
static uint32_t get_uint32_from_byte_string(const uint8_t *data, bool little_endian)
|
||||
{
|
||||
uint32_t out = 0ul;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (little_endian)
|
||||
out >>= 8u;
|
||||
else
|
||||
out <<= 8u;
|
||||
|
||||
out |= (((uint32_t)data[i]) << (little_endian ? 24u : 0u));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static void write_crc_to_byte_array(uint8_t *byte_array, uint32_t crc, uint8_t crc_size_bytes, bool little_endian)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!byte_array)
|
||||
return;
|
||||
|
||||
for (i = 0; i < crc_size_bytes; i++) {
|
||||
if (little_endian) {
|
||||
byte_array[i] = (uint8_t)(crc & 0xFFul);
|
||||
crc >>= 8u;
|
||||
} else {
|
||||
byte_array[i] = (uint8_t)((crc & 0xFF000000ul) >> 24u);
|
||||
crc <<= 8u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void free_elf_section_element(struct elf_section *sec)
|
||||
{
|
||||
if (sec) {
|
||||
if (sec->name)
|
||||
free(sec->name);
|
||||
sec->name = NULL;
|
||||
free(sec);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *section_type_to_str(Elf64_Word type)
|
||||
{
|
||||
switch (type) {
|
||||
case SHT_NULL:
|
||||
return "NULL";
|
||||
case SHT_PROGBITS:
|
||||
return "PROGBITS";
|
||||
case SHT_SYMTAB:
|
||||
return "SYMTAB";
|
||||
case SHT_STRTAB:
|
||||
return "STRTAB";
|
||||
case SHT_NOBITS:
|
||||
return "NOBITS";
|
||||
case SHT_ARM_EXIDX:
|
||||
return "ARM_EXIDX";
|
||||
case SHT_INIT_ARRAY:
|
||||
return "INIT_ARRAY";
|
||||
case SHT_FINI_ARRAY:
|
||||
return "FINI_ARRAY";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static void print_sections(elfpatch_handle_t *ep)
|
||||
{
|
||||
SlList *iter;
|
||||
ft_table_t *table;
|
||||
const struct elf_section *section;
|
||||
|
||||
ret_if_ep_err(ep);
|
||||
|
||||
if (!ep->sections) {
|
||||
print_err("No sections found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reporting_get_verbosity())
|
||||
return;
|
||||
|
||||
table = ft_create_table();
|
||||
|
||||
/* Write header */
|
||||
ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);
|
||||
ft_write_ln(table, "Section", "Type", "Size", "Address", "File Offset");
|
||||
|
||||
for (iter = ep->sections; iter; iter = sl_list_next(iter)) {
|
||||
section = (const struct elf_section *)iter->data;
|
||||
if (!section)
|
||||
continue;
|
||||
ft_printf_ln(table, "%s|%s|%lu|0x%p|0x%p",
|
||||
section->name,
|
||||
section_type_to_str(section->section_header.sh_type),
|
||||
section->section_header.sh_size,
|
||||
(void *)section->section_header.sh_addr,
|
||||
(void *)section->section_header.sh_offset
|
||||
);
|
||||
}
|
||||
|
||||
print_debug("%s\n", ft_to_string(table));
|
||||
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
|
||||
static SlList *elf_patch_get_sections(elfpatch_handle_t *ep)
|
||||
{
|
||||
SlList *ret = NULL;
|
||||
Elf_Scn *scn;
|
||||
struct elf_section *sec;
|
||||
char *name;
|
||||
size_t shstrndx;
|
||||
|
||||
ret_val_if_ep_err(ep, NULL);
|
||||
|
||||
if (ep->sections)
|
||||
sl_list_free_full(ret, (void (*)(void *))free_elf_section_element);
|
||||
ep->sections = NULL;
|
||||
|
||||
if (elf_getshdrstrndx (ep->elf , &shstrndx) != 0) {
|
||||
print_err("ELF error: %s\n", elf_errmsg(-1));
|
||||
goto ret_free_section_list;
|
||||
}
|
||||
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(ep->elf, scn)) != NULL) {
|
||||
sec = (struct elf_section *)calloc(1u, sizeof(struct elf_section));
|
||||
sec->name = NULL;
|
||||
sec->scn = scn;
|
||||
|
||||
if (gelf_getshdr(scn, &sec->section_header) != &sec->section_header) {
|
||||
print_err("Error reading section header: %s\n", elf_errmsg(-1));
|
||||
free(sec);
|
||||
continue;
|
||||
}
|
||||
name = elf_strptr(ep->elf, shstrndx, sec->section_header.sh_name);
|
||||
if (name) {
|
||||
sec->name = strdup(name);
|
||||
}
|
||||
ret = sl_list_append(ret, sec);
|
||||
}
|
||||
|
||||
ep->sections = ret;
|
||||
|
||||
print_sections(ep);
|
||||
|
||||
return ret;
|
||||
|
||||
ret_free_section_list:
|
||||
sl_list_free_full(ret, (void (*)(void *))free_elf_section_element);
|
||||
ret = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int elf_patch_update_info(elfpatch_handle_t *ep)
|
||||
{
|
||||
Elf_Kind ek;
|
||||
const char *type_string = "unrecognized";
|
||||
|
||||
ret_val_if_ep_err(ep, -1001);
|
||||
|
||||
ek = elf_kind(ep->elf);
|
||||
|
||||
switch (ek) {
|
||||
case ELF_K_AR:
|
||||
type_string = "archive";
|
||||
break;
|
||||
case ELF_K_ELF:
|
||||
type_string = "elf object";
|
||||
break;
|
||||
default:
|
||||
/* Unrecognized is the default. Do nothing */
|
||||
break;
|
||||
}
|
||||
print_debug("ELF File Type: %s\n", type_string);
|
||||
|
||||
if (ek != ELF_K_ELF)
|
||||
return -1;
|
||||
|
||||
gelf_getehdr(ep->elf, &ep->ehdr);
|
||||
ep->class = gelf_getclass(ep->elf);
|
||||
|
||||
switch (ep->class) {
|
||||
case ELFCLASS32:
|
||||
print_debug("ELF class: 32 bit\n");
|
||||
break;
|
||||
case ELFCLASS64:
|
||||
print_debug("ELF class: 64 bit\n");
|
||||
break;
|
||||
default:
|
||||
print_err("Unsupported ELF class: %d\n", ep->class);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!elf_patch_get_sections(ep)) {
|
||||
print_err("No sections in file.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
elfpatch_handle_t *elf_patch_open(const char *path, bool readonly)
|
||||
{
|
||||
struct elfpatch *ep;
|
||||
|
||||
/* This is important to guarantee structure packing behavior */
|
||||
CRC_OUT_CHECK_STRUCT_SIZES;
|
||||
|
||||
if (!path) {
|
||||
print_err("Internal error while opeing ELF file. No path specified\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ep = (struct elfpatch *)calloc(1u, sizeof(struct elfpatch));
|
||||
ep->magic = ELFPATCH_MAGIC;
|
||||
ep->readonly = readonly;
|
||||
|
||||
ep->fd = open(path, readonly ? O_RDONLY : O_RDWR, 0);
|
||||
if (ep->fd < 0) {
|
||||
print_err("Error opening file: %s\n", path);
|
||||
goto free_struct;
|
||||
}
|
||||
ep->elf = elf_begin(ep->fd, readonly ? ELF_C_READ : ELF_C_RDWR, NULL);
|
||||
if (!ep->elf) {
|
||||
print_err("[LIBELF] %s\n", elf_errmsg(-1));
|
||||
goto close_fd;
|
||||
}
|
||||
|
||||
if (elf_patch_update_info(ep)) {
|
||||
print_err("File malformatted. Cannot use for CRC patching\n");
|
||||
goto close_elf;
|
||||
}
|
||||
|
||||
return (elfpatch_handle_t *)ep;
|
||||
close_elf:
|
||||
if (ep->elf) {
|
||||
elf_end(ep->elf);
|
||||
ep->elf = NULL;
|
||||
}
|
||||
close_fd:
|
||||
if (ep->fd > 0) {
|
||||
close(ep->fd);
|
||||
}
|
||||
free_struct:
|
||||
free(ep);
|
||||
ep = NULL;
|
||||
return (elfpatch_handle_t *)ep;
|
||||
}
|
||||
|
||||
static struct elf_section *find_section_in_list(SlList *list, const char *name)
|
||||
{
|
||||
SlList *iter;
|
||||
struct elf_section *ret = NULL;
|
||||
struct elf_section *sec;
|
||||
|
||||
for (iter = list; iter; iter = sl_list_next(iter)) {
|
||||
sec = (struct elf_section *)iter->data;
|
||||
if (strcmp(sec->name, name) == 0) {
|
||||
ret = sec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int elf_patch_check_for_section(elfpatch_handle_t *ep, const char *section)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret_val_if_ep_err(ep, -1001);
|
||||
|
||||
ret = find_section_in_list(ep->sections, section) ? 0 : -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t translate_index(size_t index, enum granularity granularity, bool little_endian)
|
||||
{
|
||||
size_t word_idx;
|
||||
size_t part_idx;
|
||||
size_t d_index;
|
||||
size_t gran_in_bytes;
|
||||
|
||||
if (!little_endian || granularity == GRANULARITY_BYTE)
|
||||
return index;
|
||||
|
||||
gran_in_bytes = (size_t)granularity / 8u;
|
||||
word_idx = index / gran_in_bytes;
|
||||
part_idx = index - word_idx * gran_in_bytes;
|
||||
|
||||
d_index = word_idx * gran_in_bytes + gran_in_bytes - 1u - part_idx;
|
||||
|
||||
return d_index;
|
||||
}
|
||||
|
||||
int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *section, struct crc_calc *crc,
|
||||
enum granularity granularity, bool little_endian)
|
||||
{
|
||||
const struct elf_section *sec;
|
||||
Elf_Data *data;
|
||||
size_t idx;
|
||||
unsigned int gran_in_bytes = (unsigned int)granularity / 8u;
|
||||
unsigned int padding_count = 0u;
|
||||
|
||||
ret_val_if_ep_err(ep, -1001);
|
||||
if (!section || !crc)
|
||||
return -1000;
|
||||
|
||||
/* Find section */
|
||||
sec = find_section_in_list(ep->sections, section);
|
||||
if (!sec) {
|
||||
print_err("Cannot find section %s\n", section);
|
||||
return -1;
|
||||
}
|
||||
|
||||
data = elf_getdata(sec->scn, NULL);
|
||||
if (!data) {
|
||||
print_err("Error reading section data from %s: %s\n", section, elf_errmsg(-1));
|
||||
return -1;
|
||||
}
|
||||
|
||||
print_debug("Section data length: %lu\n", data->d_size);
|
||||
if (!data->d_size)
|
||||
print_err("Section %s contains no data.\n", section);
|
||||
|
||||
/* If big endian or granularity is byte, simply compute CRC. No reordering is necessary */
|
||||
if (!little_endian || granularity == GRANULARITY_BYTE) {
|
||||
crc_push_bytes(crc, data->d_buf, data->d_size);
|
||||
} else {
|
||||
/* Little endian case with > byte sized chunks */
|
||||
|
||||
/* Check granularity vs size of section */
|
||||
padding_count = (gran_in_bytes - data->d_size % gran_in_bytes) % gran_in_bytes;
|
||||
if (padding_count) {
|
||||
print_err("Section '%s' is not a multiple size of the given granularity. %u zero padding bytes will be added.\n",
|
||||
section, padding_count);
|
||||
}
|
||||
|
||||
for (idx = 0; idx < data->d_size; idx++) {
|
||||
crc_push_byte(crc, ((char *)data->d_buf)[translate_index(idx, granularity, little_endian)]);
|
||||
}
|
||||
|
||||
/* Pad with zeroes */
|
||||
for (idx = 0; idx < padding_count; idx++) {
|
||||
crc_push_byte(crc, 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t calculate_needed_space_for_crcs(elfpatch_handle_t *ep,
|
||||
enum crc_format format,
|
||||
bool check_start_magic, bool check_end_magic,
|
||||
uint8_t crc_size_bytes, size_t crc_count)
|
||||
{
|
||||
size_t needed_space = 0ull;
|
||||
|
||||
switch (format) {
|
||||
case FORMAT_BARE:
|
||||
needed_space = crc_size_bytes * crc_count;
|
||||
break;
|
||||
case FORMAT_STRUCT:
|
||||
/* Calculate space for CRCs including sentinel struct at the end */
|
||||
needed_space = (crc_count + 1) *
|
||||
(ep->class == ELFCLASS32
|
||||
? sizeof(struct crc_out_struct_32bit)
|
||||
: sizeof(struct crc_out_struct_64bit));
|
||||
break;
|
||||
default:
|
||||
needed_space = 0;
|
||||
print_err("Unsupported CRC output format\n");
|
||||
}
|
||||
/* Add existing magic numbers to required space */
|
||||
if (check_start_magic) {
|
||||
needed_space += 4u;
|
||||
/* Account for paading after 32 bit magic value in case of structure usage on 64 bit systems */
|
||||
if (ep->class == ELFCLASS64 && format == FORMAT_STRUCT)
|
||||
needed_space += 4u;
|
||||
}
|
||||
if (check_end_magic)
|
||||
needed_space += 4u;
|
||||
|
||||
return needed_space;
|
||||
}
|
||||
|
||||
int elf_patch_write_crcs_to_section(elfpatch_handle_t *ep, const char *section, const SlList *section_name_list,
|
||||
const uint32_t *crcs, uint8_t crc_size_bits, uint32_t start_magic, uint32_t end_magic,
|
||||
bool check_start_magic, bool check_end_magic, enum crc_format format, bool little_endian)
|
||||
{
|
||||
int ret = -1;
|
||||
struct elf_section *output_section;
|
||||
struct elf_section *input_section;
|
||||
Elf_Data *output_sec_data;
|
||||
const SlList *iter;
|
||||
size_t needed_space;
|
||||
size_t crc_count;
|
||||
uint8_t crc_size_bytes;
|
||||
uint8_t *sec_bytes;
|
||||
size_t idx;
|
||||
struct crc_out_struct_32bit crc_32bit;
|
||||
struct crc_out_struct_64bit crc_64bit;
|
||||
|
||||
ret_val_if_ep_err(ep, -1000);
|
||||
|
||||
print_debug("== Patch output file ==\n");
|
||||
|
||||
if (crc_size_bits < 1u || crc_size_bits > 32u) {
|
||||
print_err("Unsupported CRC size: %u", (unsigned int)crc_size_bits);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* All pointer parameters are required */
|
||||
if (!section || !section_name_list || !crcs)
|
||||
return -1000;
|
||||
|
||||
output_section = find_section_in_list(ep->sections, section);
|
||||
if (!output_section) {
|
||||
print_err("Cannot find output section '%s' to place CRCs. Exiting.\n", section);
|
||||
goto ret_err;
|
||||
}
|
||||
|
||||
/* Get data object of section */
|
||||
output_sec_data = elf_getdata(output_section->scn, NULL);
|
||||
sec_bytes = (uint8_t *)output_sec_data->d_buf;
|
||||
|
||||
/* Check the start and end magics */
|
||||
if (check_start_magic) {
|
||||
if (get_uint32_from_byte_string(sec_bytes, little_endian) != start_magic) {
|
||||
print_err("Start magic does not match: expected: 0x%08x, got: 0x%08x\n",
|
||||
start_magic, get_uint32_from_byte_string(sec_bytes, little_endian));
|
||||
goto ret_err;
|
||||
}
|
||||
print_debug("Start magic matching: 0x%08x\n", start_magic);
|
||||
}
|
||||
if (check_end_magic) {
|
||||
if (get_uint32_from_byte_string(&sec_bytes[output_sec_data->d_size - 4], little_endian) != end_magic) {
|
||||
print_err("End magic does not match: expected: 0x%08x, got: 0x%08x\n",
|
||||
end_magic,
|
||||
get_uint32_from_byte_string(&sec_bytes[output_sec_data->d_size - 4], little_endian));
|
||||
goto ret_err;
|
||||
}
|
||||
print_debug("End magic matching: 0x%08x\n", end_magic);
|
||||
}
|
||||
|
||||
/* Calculate Bytes needed for CRC */
|
||||
crc_size_bytes = (crc_size_bits + 7u) / 8u;
|
||||
crc_count = sl_list_length(section_name_list);
|
||||
if (crc_count < 1) {
|
||||
/* No CRCs to patch... */
|
||||
ret = -1;
|
||||
print_err("No CRCs to patch. This is probably an internal error.\n");
|
||||
goto ret_err;
|
||||
}
|
||||
|
||||
print_debug("Single CRC requires %u bytes.\n", (unsigned int)crc_size_bytes);
|
||||
|
||||
needed_space = calculate_needed_space_for_crcs(ep, format, check_start_magic, check_end_magic, crc_size_bytes,
|
||||
crc_count);
|
||||
|
||||
print_debug("Required space for %zu CRCs %s: %zu (available: %zu)\n",
|
||||
crc_count,
|
||||
(check_start_magic || check_end_magic ? "including magic values" : ""),
|
||||
needed_space,
|
||||
output_sec_data->d_size
|
||||
);
|
||||
if (needed_space > output_sec_data->d_size) {
|
||||
print_err("Not enough space in section. %zu bytes available but %zu needed\n",
|
||||
output_sec_data->d_size, needed_space);
|
||||
ret = -1;
|
||||
goto ret_err;
|
||||
}
|
||||
|
||||
/* Checks finished. Write data to output section */
|
||||
|
||||
if (format == FORMAT_BARE) {
|
||||
if (check_start_magic)
|
||||
sec_bytes += 4u;
|
||||
for (iter = section_name_list, idx = 0; iter; iter = sl_list_next(iter), idx++) {
|
||||
print_debug("Write CRC 0x%08x (%u bytes) for section %s\n", crcs[idx],
|
||||
(unsigned int)crc_size_bytes,
|
||||
iter->data);
|
||||
write_crc_to_byte_array(sec_bytes, crcs[idx], crc_size_bytes, little_endian);
|
||||
sec_bytes += crc_size_bytes;
|
||||
}
|
||||
} else if (format == FORMAT_STRUCT) {
|
||||
if (check_start_magic)
|
||||
sec_bytes += 4u;
|
||||
if (check_start_magic && ep->class == ELFCLASS64)
|
||||
sec_bytes += 4u;
|
||||
|
||||
for (iter = section_name_list, idx = 0; iter; iter = sl_list_next(iter), idx++) {
|
||||
input_section = find_section_in_list(ep->sections, (const char *)iter->data);
|
||||
if (!input_section) {
|
||||
print_err("Internal error. Please report this. %s:%d ", __FILE__, __LINE__);
|
||||
ret = -2;
|
||||
goto ret_err;
|
||||
}
|
||||
print_debug("Write CRC 0x%08x (%u bytes) for section %s.\n", crcs[idx],
|
||||
(unsigned int)crc_size_bytes,
|
||||
iter->data);
|
||||
print_debug("Corresponding input section at 0x%"PRIx64", length: %"PRIu64"\n",
|
||||
(uint64_t)input_section->section_header.sh_addr,
|
||||
(uint64_t)input_section->section_header.sh_size);
|
||||
if (ep->class == ELFCLASS32) {
|
||||
crc_32bit.crc = crcs[idx];
|
||||
crc_32bit.length = (uint32_t)input_section->section_header.sh_size;
|
||||
crc_32bit.start_address = (uint32_t)input_section->section_header.sh_addr;
|
||||
memcpy(sec_bytes, &crc_32bit, sizeof(crc_32bit));
|
||||
sec_bytes += sizeof(crc_32bit);
|
||||
} else {
|
||||
/* 64 bit case */
|
||||
crc_64bit.crc = crcs[idx];
|
||||
crc_64bit._unused_dummy = 0ul;
|
||||
crc_64bit.length = (uint64_t)input_section->section_header.sh_size;
|
||||
crc_64bit.start_address = (uint64_t)input_section->section_header.sh_addr;
|
||||
memcpy(sec_bytes, &crc_64bit, sizeof(crc_64bit));
|
||||
sec_bytes += sizeof(crc_64bit);
|
||||
}
|
||||
}
|
||||
|
||||
/* Append sentinel struct */
|
||||
crc_32bit.crc = 0ul;
|
||||
crc_32bit.length = 0ul;
|
||||
crc_32bit.start_address = 0ul;
|
||||
|
||||
crc_64bit.crc = 0ul;
|
||||
crc_64bit.length = 0ull;
|
||||
crc_64bit.start_address = 0ull;
|
||||
|
||||
if (ep->class == ELFCLASS32) {
|
||||
memcpy(sec_bytes, &crc_32bit, sizeof(crc_32bit));
|
||||
} else {
|
||||
memcpy(sec_bytes, &crc_64bit, sizeof(crc_64bit));
|
||||
}
|
||||
}
|
||||
|
||||
/* Update ELF file */
|
||||
if (ep->readonly) {
|
||||
print_debug("DRY RUN: File will not be updated\n");
|
||||
ret = 0;
|
||||
} else {
|
||||
if (elf_update(ep->elf, ELF_C_WRITE) < 0) {
|
||||
print_err("Error writing ELF file: %s\n", elf_errmsg(-1));
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ret_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void elf_patch_close_and_free(elfpatch_handle_t *ep)
|
||||
{
|
||||
ret_if_ep_err(ep);
|
||||
|
||||
if (ep->elf)
|
||||
elf_end(ep->elf);
|
||||
|
||||
if (ep->fd > 0)
|
||||
close(ep->fd);
|
||||
|
||||
if (ep->sections)
|
||||
sl_list_free_full(ep->sections, (void (*)(void *))free_elf_section_element);
|
||||
ep->sections = NULL;
|
||||
|
||||
ep->elf = NULL;
|
||||
ep->fd = 0;
|
||||
|
||||
free(ep);
|
||||
}
|
437
src/main.c
Normal file
437
src/main.c
Normal file
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* This file is part of patchelfcrc .
|
||||
* Copyright (c) 2022 Mario Hüttel.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 only.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libelf.h>
|
||||
#include <argp.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <patchelfcrc/named_crcs.h>
|
||||
#include <patchelfcrc/crc.h>
|
||||
#include <patchelfcrc/version.h>
|
||||
#include <linklist-lib/singly-linked-list.h>
|
||||
#include <patchelfcrc/reporting.h>
|
||||
#include <patchelfcrc/elfpatch.h>
|
||||
#include <fort.h>
|
||||
|
||||
const char *argp_program_bug_address = "<mario [dot] huettel [at] linux [dot] com>";
|
||||
|
||||
#define ARG_KEY_DRY_RUN (1)
|
||||
#define ARG_KEY_START_MAGIC (2)
|
||||
#define ARG_KEY_END_MAGIC (3)
|
||||
#define ARG_KEY_LIST (4)
|
||||
|
||||
struct command_line_options {
|
||||
bool little_endian;
|
||||
bool dry_run;
|
||||
bool verbose;
|
||||
enum granularity granularity;
|
||||
enum crc_format format;
|
||||
struct crc_settings crc;
|
||||
bool has_start_magic;
|
||||
uint32_t start_magic;
|
||||
bool has_end_magic;
|
||||
uint32_t end_magic;
|
||||
bool list;
|
||||
SlList *section_list;
|
||||
const char *elf_path;
|
||||
const char *output_section;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Parse command line options
|
||||
* @param key Option key
|
||||
* @param arg Argument passed
|
||||
* @param state State of ARGP parser
|
||||
* @return 0 No error
|
||||
* @return ARGP_ERR_UNKNOWN in case of an unknown option
|
||||
*/
|
||||
static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
||||
{
|
||||
struct command_line_options *args = (struct command_line_options *)state->input;
|
||||
const struct named_crc *looked_up_crc;
|
||||
char *endptr;
|
||||
|
||||
switch (key) {
|
||||
case ARG_KEY_DRY_RUN:
|
||||
args->dry_run = true;
|
||||
args->verbose = true;
|
||||
break;
|
||||
case ARG_KEY_START_MAGIC:
|
||||
args->has_start_magic = true;
|
||||
args->start_magic = strtoul(arg, NULL, 0);
|
||||
break;
|
||||
case ARG_KEY_END_MAGIC:
|
||||
args->has_end_magic = true;
|
||||
args->end_magic = strtoul(arg, NULL, 0);
|
||||
break;
|
||||
case ARG_KEY_LIST:
|
||||
args->list = true;
|
||||
break;
|
||||
case 'p':
|
||||
/* Polyniomial */
|
||||
args->crc.polynomial = strtoull(arg, &endptr, 0);
|
||||
if (endptr == arg) {
|
||||
if ((looked_up_crc = lookup_named_crc(arg))) {
|
||||
memcpy(&args->crc, &looked_up_crc->settings, sizeof(struct crc_settings));
|
||||
} else {
|
||||
argp_error(state, "Error parsing polynomial: %s\n", arg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
args->little_endian = true;
|
||||
break;
|
||||
case 'v':
|
||||
args->verbose = true;
|
||||
break;
|
||||
case 'S':
|
||||
/* Section */
|
||||
args->section_list = sl_list_append(args->section_list, strdup(arg));
|
||||
break;
|
||||
case 'g':
|
||||
if (!strcmp(arg, "byte"))
|
||||
args->granularity = GRANULARITY_BYTE;
|
||||
else if (!strcmp(arg, "halfword"))
|
||||
args->granularity = GRANULARITY_16BIT;
|
||||
else if (!strcmp(arg, "word"))
|
||||
args->granularity = GRANULARITY_32BIT;
|
||||
else
|
||||
argp_error(state, "Error parsing granularity: %s\n", arg);
|
||||
break;
|
||||
case 'F':
|
||||
if (!strcmp(arg, "bare"))
|
||||
args->format = FORMAT_BARE;
|
||||
else if (!strcmp(arg, "struct"))
|
||||
args->format = FORMAT_STRUCT;
|
||||
else
|
||||
argp_error(state, "Error parsing output format: %s\n", arg);
|
||||
break;
|
||||
case 'O':
|
||||
args->output_section = arg;
|
||||
break;
|
||||
case 'r':
|
||||
args->crc.rev = true;
|
||||
break;
|
||||
case 's':
|
||||
args->crc.start_value = strtoul(arg, NULL, 0);
|
||||
break;
|
||||
case 'x':
|
||||
args->crc.xor = strtoul(arg, NULL, 0);
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
if (state->arg_num >= 1)
|
||||
argp_usage(state);
|
||||
else
|
||||
args->elf_path = arg;
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_cmdline_options(int *argc, char ***argv, struct command_line_options *cmd_opts)
|
||||
{
|
||||
const int crc_param_group = 1;
|
||||
error_t err;
|
||||
|
||||
if (!argc || !argv)
|
||||
return -1000;
|
||||
|
||||
static struct argp_option options[] = {
|
||||
{"little-endian", 'l', 0, 0, "Memory image is little endian. Only relevant if granularity is greater than a single byte", 0},
|
||||
{"granularity", 'g', "GRANULARITY", 0, "Granularity to calculate the CRC for", 0},
|
||||
{"poly", 'p', "POLYNOMIAL", 0, "Polynomial to use", crc_param_group},
|
||||
{"start-value", 's', "STARTVALUE", 0, "Start value for CRC calculation", crc_param_group},
|
||||
{"reversed", 'r', 0, 0, "Bit reversed CRC", crc_param_group},
|
||||
{"xor-out", 'x', "XORVAL", 0, "XOR the output with XORVAL. Default 0x0", crc_param_group},
|
||||
{"dry-run", ARG_KEY_DRY_RUN, 0, 0, "Dry run. Caclualate CRCs but do not patch output file. Implicitly activates verbose mode.", 0},
|
||||
{"verbose", 'v', 0, 0, "Verbose output", 0},
|
||||
{"section", 'S', "SEC", 0, "Section to calculate CRC for", 2},
|
||||
{"output-section", 'O', "OUTPUTSEC", 0, "Output section for generated 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},
|
||||
{"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},
|
||||
/* Sentinel */
|
||||
{NULL, 0, 0, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static struct argp arg_parser = {
|
||||
options,
|
||||
parse_opt,
|
||||
"ELF",
|
||||
NULL,
|
||||
0, 0, 0
|
||||
};
|
||||
|
||||
err = argp_parse(&arg_parser, *argc, *argv, 0, 0, cmd_opts);
|
||||
|
||||
return err ? -1 : 0;
|
||||
}
|
||||
|
||||
static void prepare_default_opts(struct command_line_options *opts)
|
||||
{
|
||||
opts->little_endian = false;
|
||||
opts->verbose = false;
|
||||
opts->granularity = GRANULARITY_BYTE;
|
||||
opts->dry_run = false;
|
||||
opts->crc.xor = 0UL;
|
||||
opts->crc.polynomial = 0x104C11DB7UL;
|
||||
opts->crc.start_value = 0xFFFFFFFFUL;
|
||||
opts->crc.rev = false;
|
||||
opts->format = FORMAT_BARE;
|
||||
opts->has_end_magic = false;
|
||||
opts->has_start_magic = false;
|
||||
opts->list = false;
|
||||
opts->section_list = NULL;
|
||||
opts->elf_path = NULL;
|
||||
opts->output_section = NULL;
|
||||
}
|
||||
|
||||
static void print_verbose_start_info(const struct command_line_options *cmd_opts)
|
||||
{
|
||||
int i;
|
||||
SlList *list_iter;
|
||||
const struct named_crc *predef_crc;
|
||||
|
||||
print_debug("Start CRC patching\n");
|
||||
print_debug("Endianess: %s endian\n", (cmd_opts->little_endian ? "little" : "big"));
|
||||
print_debug("Granularity: %u bits\n", (unsigned int)cmd_opts->granularity);
|
||||
if (cmd_opts->has_start_magic)
|
||||
print_debug("Checking for start magic: 0x%08x\n", (unsigned int)cmd_opts->start_magic);
|
||||
if (cmd_opts->has_end_magic)
|
||||
print_debug("Checking for end magic: 0x%08x\n", (unsigned int)cmd_opts->end_magic);
|
||||
if (cmd_opts->dry_run)
|
||||
print_debug("Dry run mode selected. Will not touch ELF file.\n");
|
||||
predef_crc = reverse_lookup_named_crc(&cmd_opts->crc);
|
||||
if (predef_crc) {
|
||||
print_debug("Predefined CRC detected: %s\n", predef_crc->name);
|
||||
} else {
|
||||
print_debug("Generator polynomial: 0x%lx\n", cmd_opts->crc.polynomial);
|
||||
print_debug("Start value: 0x%x\n", cmd_opts->crc.start_value);
|
||||
print_debug("Output XOR: 0x%x\n", cmd_opts->crc.xor);
|
||||
print_debug("Reversed: %s\n", cmd_opts->crc.rev ? "yes" : "no");
|
||||
print_debug("CRC length: %d\n", crc_len_from_poly(cmd_opts->crc.polynomial));
|
||||
}
|
||||
|
||||
if (cmd_opts->elf_path) {
|
||||
print_debug("ELF file: %s\n", cmd_opts->elf_path);
|
||||
}
|
||||
|
||||
if (cmd_opts->output_section) {
|
||||
print_debug("Output section: %s\n", cmd_opts->output_section);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
SlList *list_iter;
|
||||
|
||||
/* Free the output section names */
|
||||
for (list_iter = opts->section_list; list_iter; list_iter = sl_list_next(list_iter)) {
|
||||
if (list_iter->data)
|
||||
free(list_iter->data);
|
||||
}
|
||||
|
||||
/* Free the section list */
|
||||
sl_list_free(opts->section_list);
|
||||
opts->section_list = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check_all_sections_present
|
||||
* @param ep
|
||||
* @param list
|
||||
* @return -1 if no sections are provided. 0 if all sections are present. -2 if setions cannot be found
|
||||
*/
|
||||
static int check_all_sections_present(elfpatch_handle_t *ep, SlList *list)
|
||||
{
|
||||
SlList *iter;
|
||||
const char *sec_name;
|
||||
int ret = 0;
|
||||
|
||||
if (!ep)
|
||||
return -1001;
|
||||
if (!list) {
|
||||
print_err("No input sections specified.\n")
|
||||
return -1;
|
||||
}
|
||||
for (iter = list; iter; iter = sl_list_next(iter)) {
|
||||
sec_name = (const char *)iter->data;
|
||||
if (!sec_name)
|
||||
continue;
|
||||
if (elf_patch_check_for_section(ep, sec_name)) {
|
||||
print_err("Cannot find section '%s'\n", sec_name);
|
||||
ret = -2;
|
||||
} else {
|
||||
print_debug("Input section '%s': found\n", sec_name);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compute CRCs over the sections in @p list
|
||||
* @param ep Elf patch
|
||||
* @param list List of section names to patch
|
||||
* @param opts Command line options. Used for CRC generation
|
||||
* @param[out] crcs Array of output CRCs. Must be large enough to hold all elements
|
||||
* @return 0 if successful
|
||||
*/
|
||||
static int compute_crcs(elfpatch_handle_t *ep, SlList *list, const struct command_line_options *opts, uint32_t *crcs)
|
||||
{
|
||||
SlList *iter;
|
||||
const char *sec_name;
|
||||
int ret = 0;
|
||||
struct crc_calc _crc;
|
||||
struct crc_calc * const crc = &_crc;
|
||||
unsigned int idx;
|
||||
|
||||
/* Construct the CRC */
|
||||
crc_init(crc, &opts->crc);
|
||||
|
||||
for (iter = list, idx = 0; iter; iter = sl_list_next(iter), idx++) {
|
||||
crc_reset(crc);
|
||||
sec_name = (const char *)iter->data;
|
||||
if (elf_patch_compute_crc_over_section(ep, sec_name, crc, opts->granularity, opts->little_endian)) {
|
||||
print_err("Error during CRC calculation. Exiting.\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
crc_finish_calc(crc);
|
||||
crcs[idx] = crc_get_value(crc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Debug-print the CRCs of sections in form of a table
|
||||
* @param[in] list List of section names
|
||||
* @param[in] crcs Array of CRCs.
|
||||
* @note The array @p crcs must be at least as long as @p list
|
||||
*/
|
||||
static void print_crcs(SlList *list, const uint32_t *crcs)
|
||||
{
|
||||
SlList *iter;
|
||||
unsigned int idx;
|
||||
const char *sec_name;
|
||||
ft_table_t *table;
|
||||
|
||||
table = ft_create_table();
|
||||
|
||||
/* Write header */
|
||||
ft_set_cell_prop(table, 0, FT_ANY_COLUMN, FT_CPROP_ROW_TYPE, FT_ROW_HEADER);
|
||||
ft_write_ln(table, "Section", "CRC");
|
||||
|
||||
for (iter = list, idx = 0; iter; iter = sl_list_next(iter), idx++) {
|
||||
sec_name = (const char *)iter->data;
|
||||
ft_printf_ln(table, "%s|0x%x", sec_name, crcs[idx]);
|
||||
}
|
||||
print_debug("Calculated CRCs:\n%s\n", ft_to_string(table));
|
||||
ft_destroy_table(table);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct command_line_options cmd_opts;
|
||||
elfpatch_handle_t *ep;
|
||||
int ret = 0;
|
||||
uint32_t *crcs;
|
||||
|
||||
prepare_default_opts(&cmd_opts);
|
||||
parse_cmdline_options(&argc, &argv, &cmd_opts);
|
||||
|
||||
if (cmd_opts.verbose || cmd_opts.dry_run)
|
||||
reporting_enable_verbose();
|
||||
print_verbose_start_info(&cmd_opts);
|
||||
|
||||
/* Check if file has been supplied */
|
||||
if (!cmd_opts.elf_path) {
|
||||
print_err("No ELF file specified. Exiting...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!cmd_opts.output_section) {
|
||||
print_err("No output section specified. Will continue but not patch file.\n");
|
||||
}
|
||||
|
||||
if (cmd_opts.list) {
|
||||
list_predefined_crcs();
|
||||
goto free_cmds;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
elf_version(EV_CURRENT);
|
||||
|
||||
/* Open the ELF file */
|
||||
ep = elf_patch_open(cmd_opts.elf_path, cmd_opts.dry_run);
|
||||
if (!ep) {
|
||||
ret = -2;
|
||||
goto free_cmds;
|
||||
}
|
||||
|
||||
/* Check if all sections are present */
|
||||
if (check_all_sections_present(ep, cmd_opts.section_list)) {
|
||||
ret = -2;
|
||||
goto free_cmds;
|
||||
}
|
||||
|
||||
/* Compute CRCs over sections */
|
||||
crcs = (uint32_t *)malloc(sl_list_length(cmd_opts.section_list) * sizeof(uint32_t));
|
||||
compute_crcs(ep, cmd_opts.section_list, &cmd_opts, crcs);
|
||||
|
||||
if (reporting_get_verbosity()) {
|
||||
print_crcs(cmd_opts.section_list, crcs);
|
||||
}
|
||||
|
||||
if (cmd_opts.output_section) {
|
||||
if (elf_patch_write_crcs_to_section(ep, cmd_opts.output_section, cmd_opts.section_list,
|
||||
crcs, 32, cmd_opts.start_magic, cmd_opts.end_magic,
|
||||
cmd_opts.has_start_magic, cmd_opts.has_end_magic,
|
||||
cmd_opts.format, cmd_opts.little_endian)) {
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
elf_patch_close_and_free(ep);
|
||||
|
||||
free_cmds:
|
||||
|
||||
free_cmd_args(&cmd_opts);
|
||||
|
||||
return ret;
|
||||
}
|
130
src/named_crcs.c
Normal file
130
src/named_crcs.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* This file is part of patchelfcrc .
|
||||
* Copyright (c) 2022 Mario Hüttel.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 only.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <patchelfcrc/named_crcs.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <fort.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define NAMED_CRC(crc_name, poly, reverse, init, outxor) { \
|
||||
.name = crc_name, \
|
||||
.settings = { \
|
||||
.polynomial = poly, \
|
||||
.xor = outxor, \
|
||||
.start_value = init, \
|
||||
.rev = reverse \
|
||||
}}
|
||||
|
||||
const struct named_crc predefined_crc_table[] = {
|
||||
NAMED_CRC("crc-8", 0x107, false, 0x00, 0x00),
|
||||
NAMED_CRC("crc-8-darc", 0x139, true, 0x00, 0x00),
|
||||
NAMED_CRC("crc-8-i-code", 0x11D, false, 0xFD, 0x00),
|
||||
NAMED_CRC("crc-8-itu", 0x107, false, 0x55, 0x55),
|
||||
NAMED_CRC("crc-8-maxim", 0x131, true, 0x00, 0x00),
|
||||
NAMED_CRC("crc-8-rohc", 0x107, true, 0xFF, 0x00),
|
||||
NAMED_CRC("crc-8-wcdma", 0x19B, true, 0x00, 0x00),
|
||||
NAMED_CRC("crc-16", 0x18005, true, 0x0000, 0x0000),
|
||||
NAMED_CRC("crc-16-buypass", 0x18005, false, 0x0000, 0x0000),
|
||||
NAMED_CRC("crc-16-dds-110", 0x18005, false, 0x800D, 0x0000),
|
||||
NAMED_CRC("crc-16-dect", 0x10589, false, 0x0001, 0x0001),
|
||||
NAMED_CRC("crc-16-dnp", 0x13D65, true, 0xFFFF, 0xFFFF),
|
||||
NAMED_CRC("crc-16-en-13757", 0x13D65, false, 0xFFFF, 0xFFFF),
|
||||
NAMED_CRC("crc-16-genibus", 0x11021, false, 0x0000, 0xFFFF),
|
||||
NAMED_CRC("crc-16-maxim", 0x18005, true, 0xFFFF, 0xFFFF),
|
||||
NAMED_CRC("crc-16-mcrf4xx", 0x11021, true, 0xFFFF, 0x0000),
|
||||
NAMED_CRC("crc-16-riello", 0x11021, true, 0x554D, 0x0000),
|
||||
NAMED_CRC("crc-16-t10-dif", 0x18BB7, false, 0x0000, 0x0000),
|
||||
NAMED_CRC("crc-16-teledisk", 0x1A097, false, 0x0000, 0x0000),
|
||||
NAMED_CRC("crc-16-usb", 0x18005, true, 0x0000, 0xFFFF),
|
||||
NAMED_CRC("x-25", 0x11021, true, 0x0000, 0xFFFF),
|
||||
NAMED_CRC("xmodem", 0x11021, false, 0x0000, 0x0000),
|
||||
NAMED_CRC("modbus", 0x18005, true, 0xFFFF, 0x0000),
|
||||
NAMED_CRC("kermit", 0x11021, true, 0x0000, 0x0000),
|
||||
NAMED_CRC("crc-ccitt-false", 0x11021, false, 0xFFFF, 0x0000),
|
||||
NAMED_CRC("crc-aug-ccitt", 0x11021, false, 0x1D0F, 0x0000),
|
||||
NAMED_CRC("crc-24", 0x1864CFB, false, 0xB704CE, 0x000000),
|
||||
NAMED_CRC("crc-24-flexray-a", 0x15D6DCB, false, 0xFEDCBA, 0x000000),
|
||||
NAMED_CRC("crc-24-flexray-b", 0x15D6DCB, false, 0xABCDEF, 0x000000),
|
||||
NAMED_CRC("crc-32", 0x104C11DB7, true, 0x00000000, 0xFFFFFFFF),
|
||||
NAMED_CRC("crc-32-bzip2", 0x104C11DB7, false, 0x00000000, 0xFFFFFFFF),
|
||||
NAMED_CRC("crc-32c", 0x11EDC6F41, true, 0x00000000, 0xFFFFFFFF),
|
||||
NAMED_CRC("crc-32d", 0x1A833982B, true, 0x00000000, 0xFFFFFFFF),
|
||||
NAMED_CRC("crc-32-mpeg", 0x104C11DB7, false, 0xFFFFFFFF, 0x00000000),
|
||||
NAMED_CRC("posix", 0x104C11DB7, false, 0xFFFFFFFF, 0xFFFFFFFF),
|
||||
NAMED_CRC("crc-32q", 0x1814141AB, false, 0x00000000, 0x00000000),
|
||||
NAMED_CRC("jamcrc", 0x104C11DB7, true, 0xFFFFFFFF, 0x00000000),
|
||||
NAMED_CRC("xfer", 0x1000000AF, false, 0x00000000, 0x00000000),
|
||||
/* SENTINEL */
|
||||
{.name = NULL, .settings = {0, 0, 0, false}},
|
||||
};
|
||||
|
||||
const struct named_crc *reverse_lookup_named_crc(const struct crc_settings *settings)
|
||||
{
|
||||
const struct named_crc *iter;
|
||||
const struct named_crc *found = NULL;
|
||||
|
||||
for (iter = predefined_crc_table; iter->name; iter++) {
|
||||
if (iter->settings.polynomial == settings->polynomial &&
|
||||
iter->settings.rev == settings->rev &&
|
||||
iter->settings.start_value == settings->start_value &&
|
||||
iter->settings.xor == settings->xor) {
|
||||
found = iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
const struct named_crc *lookup_named_crc(const char *name)
|
||||
{
|
||||
const struct named_crc *iter;
|
||||
const struct named_crc *found = NULL;
|
||||
|
||||
for (iter = predefined_crc_table; iter->name; iter++) {
|
||||
if (!strcmp(iter->name, name)) {
|
||||
found = iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void list_predefined_crcs(void)
|
||||
{
|
||||
ft_table_t *table;
|
||||
const struct named_crc *iter;
|
||||
|
||||
table = ft_create_table();
|
||||
|
||||
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");
|
||||
|
||||
for (iter = predefined_crc_table; iter->name; iter++) {
|
||||
ft_printf_ln(table, "%s|0x%lx|%s|0x%x|0x%x",
|
||||
iter->name,
|
||||
iter->settings.polynomial,
|
||||
iter->settings.rev ? "yes" : "no",
|
||||
iter->settings.start_value,
|
||||
iter->settings.xor);
|
||||
}
|
||||
|
||||
printf("%s\n", ft_to_string(table));
|
||||
ft_destroy_table(table);
|
||||
}
|
45
src/reporting.c
Normal file
45
src/reporting.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of patchelfcrc.
|
||||
* Copyright (c) 2022 Mario Hüttel.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 only.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <patchelfcrc/reporting.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
static bool global_verbosity_state = false;
|
||||
|
||||
void print_debug(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
if (global_verbosity_state) {
|
||||
va_start(va, fmt);
|
||||
(void)vprintf(fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
}
|
||||
|
||||
void reporting_enable_verbose(void)
|
||||
{
|
||||
global_verbosity_state = true;
|
||||
}
|
||||
|
||||
bool reporting_get_verbosity(void)
|
||||
{
|
||||
return global_verbosity_state;
|
||||
}
|
22
src/version.c
Normal file
22
src/version.c
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* This file is part of patchelfcrc .
|
||||
* Copyright (c) 2022 Mario Hüttel.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 only.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <patchelfcrc/version.h>
|
||||
#include <generated/version.h>
|
||||
|
||||
const char *version_string = GIT_VERSION_STRING;
|
||||
const char *argp_program_version = GIT_VERSION_STRING;
|
Reference in New Issue
Block a user