Compare commits
	
		
			20 Commits
		
	
	
		
			v1.0.0-rc1
			...
			b726d5ba75
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b726d5ba75 | |||
| bfb587360d | |||
| f964ef7b60 | |||
| dd05449f36 | |||
| 3ff626134e | |||
| 29fdc841b7 | |||
| dc30188593 | |||
| 2bea5d288c | |||
| 8a0226a5ea | |||
| ed6373473c | |||
| 80b5f5b1b3 | |||
| 4fab6ffd3a | |||
| 0ee19eaea4 | |||
| 26eb480343 | |||
| 30e47d533a | |||
| faeab33375 | |||
| 7e414f8576 | |||
| 933680c80d | |||
| 891df1803e | |||
| 7be1d6a967 | 
							
								
								
									
										2
									
								
								3rdparty/libfort
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								3rdparty/libfort
									
									
									
									
										vendored
									
									
								
							 Submodule 3rdparty/libfort updated: 41237162a9...5a8f9312bd
									
								
							| @@ -1,14 +1,14 @@ | ||||
| # Maintainer: Mario Hüttel <mario (dot) huettel (!) gmx (dot) net> | ||||
|  | ||||
| pkgname=patchelfcrc | ||||
| pkgver=5e7f697 | ||||
| pkgver=v1.0.0_rc1 | ||||
| pkgrel=1 | ||||
| pkgdesc="Tool for patching CRC checksums of sections into ELF binaries" | ||||
| arch=('i686' 'x86_64') | ||||
| url="https://git.shimatta.de/mhu/patchelfcrc" | ||||
| licence=('GPLv2') | ||||
| depends=('libelf' 'libxml2') | ||||
| makedepends=('cmake' 'pandoc' 'git' 'gvim') | ||||
| makedepends=('cmake' 'pandoc' 'git' 'gvim' 'bash') | ||||
| 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") | ||||
| sha1sums=('SKIP' 'SKIP' 'SKIP') | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| cmake_minimum_required(VERSION 3.5) | ||||
| cmake_minimum_required(VERSION 3.5...3.18) | ||||
|  | ||||
| project(patchelfcrc LANGUAGES C) | ||||
|  | ||||
| @@ -28,8 +28,6 @@ pkg_check_modules(ELF REQUIRED libelf) | ||||
| find_package(Doxygen) | ||||
| find_package(LibXml2 REQUIRED) | ||||
|  | ||||
| add_subdirectory(man) | ||||
|  | ||||
| aux_source_directory("src" CFILES) | ||||
|  | ||||
| set(GEN_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/include/generated") | ||||
| @@ -37,11 +35,14 @@ set(GEN_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/include/generated") | ||||
| add_custom_target( | ||||
| 		version-header | ||||
| 	COMMAND | ||||
| 		mkdir -p ${GEN_HEADER_PATH} && bash "${CMAKE_CURRENT_SOURCE_DIR}/gen_version_header.sh" "${GEN_HEADER_PATH}/version.h" | ||||
| 		${CMAKE_COMMAND} -D SRC=${CMAKE_SOURCE_DIR}/version.h.template | ||||
| 					 -D DST=${GEN_HEADER_PATH}/version.h | ||||
| 					 -P ${CMAKE_SOURCE_DIR}/GenerateVersion.cmake | ||||
| 	WORKING_DIRECTORY | ||||
| 		${CMAKE_CURRENT_SOURCE_DIR} | ||||
| 	COMMENT "Generating version header" | ||||
| 	) | ||||
| 	add_subdirectory(man) | ||||
|  | ||||
| add_custom_target(schema-header DEPENDS "${GEN_HEADER_PATH}/schema-blob.h") | ||||
| add_custom_command( | ||||
| @@ -66,7 +67,8 @@ target_link_directories(${PROJECT_NAME} PRIVATE ${ELF_LIBRARY_DIRS} ${LIBXML2_LI | ||||
| target_include_directories(${PROJECT_NAME} PRIVATE ${ELF_INCLUDE_DIRS}) | ||||
| target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include") | ||||
| target_include_directories(${PROJECT_NAME} PRIVATE "include") | ||||
| add_dependencies(${PROJECT_NAME} version-header schema-header) | ||||
| add_dependencies(${PROJECT_NAME} schema-header) | ||||
| add_dependencies(${PROJECT_NAME} version-header) | ||||
|  | ||||
| if (DOXYGEN_FOUND) | ||||
| 	set(DOXYFILE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/doxygen/Doxyfile.in") | ||||
| @@ -83,11 +85,13 @@ if (DOXYGEN_FOUND) | ||||
|  | ||||
| 	add_custom_target(doxygen-version-header | ||||
| 		COMMAND | ||||
| 			bash ${CMAKE_CURRENT_SOURCE_DIR}/doxygen/gen-version-string.sh "${CMAKE_CURRENT_BINARY_DIR}/doxyversion.in" | ||||
| 			${CMAKE_COMMAND} -D SRC="${CMAKE_SOURCE_DIR}/doxyversion.in.template" | ||||
| 					 -D DST="${CMAKE_CURRENT_BINARY_DIR}/doxyversion.in" | ||||
| 					 -P ${CMAKE_SOURCE_DIR}/GenerateVersion.cmake | ||||
| 		WORKING_DIRECTORY | ||||
| 			${CMAKE_CURRENT_SOURCE_DIR} | ||||
| 	) | ||||
| else (DOXYGEN_FOUND) | ||||
| else  (DOXYGEN_FOUND) | ||||
| 	message("${BoldMagenta}Doxygen needs to be installed to generate the doxygen documentation${ColorReset}") | ||||
| 	message("${BoldMagenta}doxygen target will not be available${ColorReset}") | ||||
| endif (DOXYGEN_FOUND) | ||||
| endif  (DOXYGEN_FOUND) | ||||
|   | ||||
							
								
								
									
										26
									
								
								GenerateVersion.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								GenerateVersion.cmake
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| find_package(Git) | ||||
|  | ||||
| if(GIT_EXECUTABLE) | ||||
|   get_filename_component(WORKING_DIR ${SRC} DIRECTORY) | ||||
|   execute_process( | ||||
|     COMMAND ${GIT_EXECUTABLE} describe --always --dirty | ||||
|     WORKING_DIRECTORY ${WORKING_DIR} | ||||
|     OUTPUT_VARIABLE PROGRAM_GIT_VERSION | ||||
|     RESULT_VARIABLE ERROR_CODE | ||||
|     OUTPUT_STRIP_TRAILING_WHITESPACE | ||||
|     ) | ||||
|  | ||||
|   if(NOT ERROR_CODE EQUAL "0") | ||||
|     set(PROGRAM_GIT_VERSION "") | ||||
|   endif() | ||||
|  | ||||
| endif() | ||||
|  | ||||
| if(PROGRAM_GIT_VERSION STREQUAL "") | ||||
|   set(PROGRAM_GIT_VERSION 0.0.0-unknown) | ||||
|   message(WARNING "Failed to determine version from Git tags. Using default version \"${PROGRAM_GIT_VERSION}\".") | ||||
| else() | ||||
| message("Git Version: \"${PROGRAM_GIT_VERSION}\".") | ||||
| endif() | ||||
|  | ||||
| configure_file(${SRC} ${DST} @ONLY) | ||||
							
								
								
									
										1
									
								
								doxyversion.in.template
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								doxyversion.in.template
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| @PROGRAM_GIT_VERSION@ | ||||
| @@ -1 +0,0 @@ | ||||
| echo `git describe --tags --always --dirty` | ||||
| @@ -1,11 +0,0 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| if [[ -z $1 ]]; then | ||||
| 	exit -1; | ||||
| fi | ||||
|  | ||||
| ver=`git describe --tags --always --dirty` | ||||
| echo "#ifndef _VERSION_GENERATED_H_" > $1 | ||||
| echo "#define _VERSION_GENERATED_H_" >> $1 | ||||
| echo "#define GIT_VERSION_STRING \"$ver\"" >> $1 | ||||
| echo "#endif /* _VERSION_GENERATED_H_ */" >> $1 | ||||
| @@ -21,14 +21,25 @@ | ||||
|  | ||||
| #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 reporting_enable_verbose(void); | ||||
| void reporting_enable_verbose(bool state); | ||||
|  | ||||
| bool reporting_get_verbosity(void); | ||||
|  | ||||
| void reporting_init(enum reporting_color_mode mode); | ||||
|  | ||||
| #endif /* _REPORTING_H_ */ | ||||
|   | ||||
 Submodule linklist-lib updated: c20b5c2528...fdd99bad48
									
								
							| @@ -10,10 +10,10 @@ add_custom_command( | ||||
| 	OUTPUT | ||||
| 		${CMAKE_CURRENT_BINARY_DIR}/${MAN_PAGE_NAME} | ||||
| 	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 | ||||
| 	WORKING_DIRECTORY | ||||
| 		${CMAKE_CURRENT_BINARY_DIR} | ||||
| 		${CMAKE_CURRENT_SOURCE_DIR} | ||||
| 	MAIN_DEPENDENCY | ||||
| 		${CMAKE_CURRENT_SOURCE_DIR}/patchelfcrc.1.md | ||||
| ) | ||||
| ) | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| % patchelfcrc(1) 0.0.2 | ||||
| % patchelfcrc(1) !version! | ||||
| % Mario Huettel | ||||
| % October 2022 | ||||
|  | ||||
| @@ -61,7 +61,7 @@ | ||||
| : Export the calculated files to an XML file *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**, **-?** | ||||
| : Print help. | ||||
| @@ -84,6 +84,9 @@ | ||||
| **--usage** | ||||
| : Print usage hints on command line options. | ||||
|  | ||||
| **--no-color** | ||||
| : Force output on stdout and stderr to be pure text without color codes. | ||||
|  | ||||
| # EXAMPLES | ||||
|  | ||||
| **patchelfcrc** --list-crcs | ||||
| @@ -131,8 +134,8 @@ | ||||
|  | ||||
| **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. | ||||
| The output sections start and end are checked for the given magic numbers in order to assure correct memory layout. | ||||
| *CRC-32-MPEG* is used as CRC algorothm. | ||||
| 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 algorithm. | ||||
| The memory is interpreted as *little endian* and the CRC calculation granularity is a 32 bit *word*. | ||||
|  | ||||
| # BUGS | ||||
|   | ||||
							
								
								
									
										104
									
								
								src/elfpatch.c
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								src/elfpatch.c
									
									
									
									
									
								
							| @@ -30,6 +30,19 @@ | ||||
| #include <fort.h> | ||||
| #include <inttypes.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 { | ||||
| 	GElf_Shdr section_header; | ||||
| @@ -77,15 +90,16 @@ static uint32_t get_uint32_from_byte_string(const uint8_t *data, bool little_end | ||||
| 	uint32_t out = 0ul; | ||||
| 	int i; | ||||
|  | ||||
| 	/* Always shift in in big endian format */ | ||||
| 	for (i = 0; i < 4; i++) { | ||||
| 		if (little_endian) | ||||
| 			out >>= 8u; | ||||
| 		else | ||||
| 			out <<= 8u; | ||||
|  | ||||
| 		out |= (((uint32_t)data[i]) << (little_endian ? 24u : 0u)); | ||||
| 		out |= (uint32_t)data[i]; | ||||
| 	} | ||||
|  | ||||
| 	/* Swap bytes if little endian */ | ||||
| 	if (little_endian) | ||||
| 		out = bswap_32(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) | ||||
| 		return; | ||||
|  | ||||
| 	if (!little_endian) | ||||
| 		crc = bswap_32(crc); | ||||
|  | ||||
| 	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; | ||||
| 		} | ||||
| 		byte_array[i] = (uint8_t)(crc & 0xFFul); | ||||
| 		crc >>= 8u; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -136,6 +148,14 @@ static const char *section_type_to_str(Elf64_Word type) | ||||
| 		return "INIT_ARRAY"; | ||||
| 	case SHT_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: | ||||
| 		break; | ||||
| 	} | ||||
| @@ -147,6 +167,7 @@ static void print_sections(elfpatch_handle_t *ep) | ||||
| 	SlList *iter; | ||||
| 	ft_table_t *table; | ||||
| 	const struct elf_section *section; | ||||
| 	bool alloc, write, exec; | ||||
|  | ||||
| 	ret_if_ep_err(ep); | ||||
|  | ||||
| @@ -162,15 +183,23 @@ static void print_sections(elfpatch_handle_t *ep) | ||||
|  | ||||
| 	/* 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", "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)) { | ||||
| 		section = (const struct elf_section *)iter->data; | ||||
| 		if (!section) | ||||
| 			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_type_to_str(section->section_header.sh_type), | ||||
| 			     alloc ? "x" : "", | ||||
| 			     write ? "x" : "", | ||||
| 			     exec ? "x" : "", | ||||
| 			     section->section_header.sh_size, | ||||
| 			     (void *)section->section_header.sh_addr, | ||||
| 			     (void *)section->lma, | ||||
| @@ -261,6 +290,12 @@ static int elf_patch_read_program_headers(elfpatch_handle_t *ep) | ||||
| 		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)); | ||||
| 	if (!ep->program_headers) { | ||||
| 		/* Mem error. Abort. Program will crash eventually */ | ||||
| @@ -306,9 +341,11 @@ static void resolve_section_lmas(elfpatch_handle_t *ep) | ||||
| 		if (!sec) | ||||
| 			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) { | ||||
| 			/* 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; | ||||
| 		} | ||||
|  | ||||
| @@ -433,12 +470,12 @@ elfpatch_handle_t *elf_patch_open(const char *path, bool readonly, bool expect_l | ||||
| 		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"); | ||||
| 				print_warn("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"); | ||||
| 				print_warn("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]); | ||||
| @@ -524,25 +561,24 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio | ||||
| 	/* Find section */ | ||||
| 	sec = find_section_in_list(ep->sections, section); | ||||
| 	if (!sec) { | ||||
| 		print_err("Cannot find section %s\n", section); | ||||
| 		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)); | ||||
| 		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); | ||||
| 		print_err("Section '%s' contains no data.\n", section); | ||||
| 		return -2; | ||||
| 	} | ||||
|  | ||||
| 	/* NOBIT sections have a length but no data in the file. Abort in this case */ | ||||
| 	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; | ||||
| 	} | ||||
|  | ||||
| @@ -556,7 +592,7 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio | ||||
| 		/* 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", | ||||
| 			print_warn("Section '%s' is not a multiple size of the given granularity. %u zero padding bytes will be added.\n", | ||||
| 				  section, padding_count); | ||||
| 		} | ||||
|  | ||||
| @@ -596,7 +632,7 @@ static size_t calculate_needed_space_for_crcs(enum crc_format format, | ||||
| 		break; | ||||
| 	default: | ||||
| 		needed_space = 0; | ||||
| 		print_err("Unsupported CRC output format\n"); | ||||
| 		print_err("Unsupported CRC output format.\n"); | ||||
| 	} | ||||
| 	/* Add existing magic numbers to required space */ | ||||
| 	if (check_start_magic) { | ||||
| @@ -651,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_64bit crc_64bit; | ||||
| 	uint64_t in_sec_addr, in_sec_len; | ||||
| 	bool needs_byteswap; | ||||
|  | ||||
| 	ret_val_if_ep_err(ep, -1000); | ||||
|  | ||||
| @@ -748,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) | ||||
| 			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++) { | ||||
| 			crc_entry = (struct crc_entry *)iter->data; | ||||
| 			in_sec_addr = use_vma ? crc_entry->vma : crc_entry->lma; | ||||
| @@ -758,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", | ||||
| 				    in_sec_addr, | ||||
| 				    in_sec_len); | ||||
|  | ||||
| 			if (crc_data->elf_bits == 32) { | ||||
| 				crc_32bit.crc = crc_entry->crc; | ||||
| 				crc_32bit.length = (uint32_t)in_sec_len; | ||||
| 				crc_32bit.start_address = (uint32_t)in_sec_addr; | ||||
| 				crc_32bit.crc = needs_byteswap ? bswap_32(crc_entry->crc) : crc_entry->crc; | ||||
| 				crc_32bit.length = needs_byteswap ? bswap_32((uint32_t)in_sec_len) : (uint32_t)in_sec_len; | ||||
| 				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)); | ||||
| 				sec_bytes += sizeof(crc_32bit); | ||||
| 			} else { | ||||
| 				/* 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.length = in_sec_len; | ||||
| 				crc_64bit.start_address = in_sec_addr; | ||||
| 				crc_64bit.length = needs_byteswap ? bswap_64(in_sec_len) : in_sec_len; | ||||
| 				crc_64bit.start_address = needs_byteswap ? bswap_64(in_sec_addr) : in_sec_addr; | ||||
| 				memcpy(sec_bytes, &crc_64bit, sizeof(crc_64bit)); | ||||
| 				sec_bytes += sizeof(crc_64bit); | ||||
| 			} | ||||
|   | ||||
							
								
								
									
										23
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/main.c
									
									
									
									
									
								
							| @@ -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_USE_VMA (7) | ||||
| #define ARG_KEY_XSD (8) | ||||
| #define ARG_KEY_FORCE_NO_COLOR (9) | ||||
|  | ||||
| struct command_line_options { | ||||
| 	bool force_nocolor; | ||||
| 	bool little_endian; | ||||
| 	bool dry_run; | ||||
| 	bool verbose; | ||||
| @@ -104,6 +106,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) | ||||
| 	case ARG_KEY_USE_VMA: | ||||
| 		args->use_vma = true; | ||||
| 		break; | ||||
| 	case ARG_KEY_FORCE_NO_COLOR: | ||||
| 		args->force_nocolor = true; | ||||
| 		break; | ||||
| 	case 'p': | ||||
| 		/* Polyniomial */ | ||||
| 		args->crc.polynomial = strtoull(arg, &endptr, 0); | ||||
| @@ -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}, | ||||
| 		{"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}, | ||||
| 		{"no-color", ARG_KEY_FORCE_NO_COLOR, 0, 0, "Force the output to be text only without colors", 0}, | ||||
| 		/* Sentinel */ | ||||
| 		{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->export_xml = NULL; | ||||
| 	opts->import_xml = NULL; | ||||
|     opts->force_nocolor = false; | ||||
| } | ||||
|  | ||||
| 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"); | ||||
| @@ -272,11 +277,6 @@ static void print_verbose_start_info(const struct command_line_options *cmd_opts | ||||
|  | ||||
| 	if (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) | ||||
| @@ -425,8 +425,11 @@ int main(int argc, char **argv) | ||||
| 		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) | ||||
| 		reporting_enable_verbose(); | ||||
| 		reporting_enable_verbose(true); | ||||
|  | ||||
| 	print_verbose_start_info(&cmd_opts); | ||||
|  | ||||
| @@ -450,7 +453,7 @@ int main(int argc, char **argv) | ||||
| 		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) | ||||
| 		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"); | ||||
|  | ||||
| 	/* Prepare libelf for use with the latest ELF version */ | ||||
| 	elf_version(EV_CURRENT); | ||||
| @@ -492,7 +495,7 @@ int main(int argc, char **argv) | ||||
|  | ||||
| 	if (cmd_opts.export_xml) { | ||||
| 		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; | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										101
									
								
								src/reporting.c
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								src/reporting.c
									
									
									
									
									
								
							| @@ -19,9 +19,66 @@ | ||||
| #include <patchelfcrc/reporting.h> | ||||
| #include <stdarg.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdbool.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| 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, ...) | ||||
| { | ||||
| @@ -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) | ||||
| { | ||||
| 	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; | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										4
									
								
								version.h.template
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								version.h.template
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| #ifndef _GENRATED_VERSION_H_ | ||||
| #define _GENRATED_VERSION_H_ | ||||
| #define GIT_VERSION_STRING "@PROGRAM_GIT_VERSION@" | ||||
| #endif /* _GENRATED_VERSION_H_ */ | ||||
		Reference in New Issue
	
	Block a user