Implement first working draft of CRC patching
This commit is contained in:
		
							
								
								
									
										2
									
								
								crc.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								crc.c
									
									
									
									
									
								
							@@ -1,5 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
 * This file is part of patchelfcrc .
 | 
					 * This file is part of patchelfcrc.
 | 
				
			||||||
 * Copyright (c) 2022 Mario Hüttel.
 | 
					 * Copyright (c) 2022 Mario Hüttel.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This program is free software: you can redistribute it and/or modify
 | 
					 * This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										164
									
								
								elfpatch.c
									
									
									
									
									
								
							
							
						
						
									
										164
									
								
								elfpatch.c
									
									
									
									
									
								
							@@ -43,7 +43,46 @@ struct elfpatch {
 | 
				
			|||||||
	} \
 | 
						} \
 | 
				
			||||||
	} while(0)
 | 
						} while(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define print_err(fmt, ...) fprintf(stderr, (fmt), ## __VA_ARGS__);
 | 
					/**
 | 
				
			||||||
 | 
					 * @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)
 | 
					static void free_elf_section_element(struct elf_section *sec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -278,7 +317,6 @@ static struct elf_section *find_section_in_list(SlList *list, const char *name)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -368,6 +406,128 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio
 | 
				
			|||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
						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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (format != FORMAT_BARE) {
 | 
				
			||||||
 | 
							print_err("Currently only bare format is supported!\n");
 | 
				
			||||||
 | 
							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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						print_debug("CRC requires %u bytes.\n", (unsigned int)crc_size_bytes);
 | 
				
			||||||
 | 
						switch (format) {
 | 
				
			||||||
 | 
						case FORMAT_BARE:
 | 
				
			||||||
 | 
							needed_space = crc_size_bytes * crc_count;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							needed_space = 0;
 | 
				
			||||||
 | 
							print_err("Unsupported CRC output format\n");
 | 
				
			||||||
 | 
							goto ret_err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/* Add existing magic numbers to required space */
 | 
				
			||||||
 | 
						if (check_start_magic)
 | 
				
			||||||
 | 
							needed_space += 4u;
 | 
				
			||||||
 | 
						if (check_end_magic)
 | 
				
			||||||
 | 
							needed_space += 4u;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Checks finished. Write data to output section */
 | 
				
			||||||
 | 
						if (format == FORMAT_BARE) {
 | 
				
			||||||
 | 
							if (check_start_magic)
 | 
				
			||||||
 | 
								sec_bytes += 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* 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)
 | 
					void elf_patch_close_and_free(elfpatch_handle_t *ep)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ret_if_ep_err(ep);
 | 
						ret_if_ep_err(ep);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@
 | 
				
			|||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <patchelfcrc/crc.h>
 | 
					#include <patchelfcrc/crc.h>
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <linklist-lib/singly-linked-list.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct elfpatch elfpatch_handle_t;
 | 
					typedef struct elfpatch elfpatch_handle_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -13,6 +14,10 @@ enum granularity {
 | 
				
			|||||||
    GRANULARITY_32BIT = 32,
 | 
					    GRANULARITY_32BIT = 32,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum crc_format {
 | 
				
			||||||
 | 
					    FORMAT_BARE = 0,
 | 
				
			||||||
 | 
					    FORMAT_STRUCT,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
elfpatch_handle_t *elf_patch_open(const char *path, bool readonly);
 | 
					elfpatch_handle_t *elf_patch_open(const char *path, bool readonly);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,4 +33,17 @@ int elf_patch_compute_crc_over_section(elfpatch_handle_t *ep, const char *sectio
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void elf_patch_close_and_free(elfpatch_handle_t *ep);
 | 
					void elf_patch_close_and_free(elfpatch_handle_t *ep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief Write CRCs to output section. This will have no effect, if file is opened read onyl
 | 
				
			||||||
 | 
					 * @param ep Elf patch object
 | 
				
			||||||
 | 
					 * @param[in] section Section name to place CRCs in
 | 
				
			||||||
 | 
					 * @param[in] section_name_list The list of sections the data belongs to
 | 
				
			||||||
 | 
					 * @param[in] crcs CRCs. Must be of the same lenght as the \p section_name_list
 | 
				
			||||||
 | 
					 * @return 0 Success
 | 
				
			||||||
 | 
					 * @return -1000 Parameter error
 | 
				
			||||||
 | 
					 * @return -1 internal error
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
#endif /* _ELFPATCH_H_ */
 | 
					#endif /* _ELFPATCH_H_ */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <stdbool.h>
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define print_err(fmt, ...) fprintf(stderr, (fmt), ## __VA_ARGS__);
 | 
					#define print_err(fmt, ...) fprintf(stderr, "[ERR] " fmt, ## __VA_ARGS__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void print_debug(const char *fmt, ...);
 | 
					void print_debug(const char *fmt, ...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
 Submodule linklist-lib updated: 18b3ab377a...c20b5c2528
									
								
							
							
								
								
									
										27
									
								
								main.c
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								main.c
									
									
									
									
									
								
							@@ -31,11 +31,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const char *argp_program_bug_address = "<mario [dot] huettel [at] linux [dot] com>";
 | 
					const char *argp_program_bug_address = "<mario [dot] huettel [at] linux [dot] com>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum crc_format {
 | 
					 | 
				
			||||||
	FORMAT_BARE = 0,
 | 
					 | 
				
			||||||
	FORMAT_STRUCT,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define ARG_KEY_DRY_RUN (1)
 | 
					#define ARG_KEY_DRY_RUN (1)
 | 
				
			||||||
#define ARG_KEY_START_MAGIC (2)
 | 
					#define ARG_KEY_START_MAGIC (2)
 | 
				
			||||||
#define ARG_KEY_END_MAGIC (3)
 | 
					#define ARG_KEY_END_MAGIC (3)
 | 
				
			||||||
@@ -55,6 +50,7 @@ struct command_line_options {
 | 
				
			|||||||
	bool list;
 | 
						bool list;
 | 
				
			||||||
	SlList *section_list;
 | 
						SlList *section_list;
 | 
				
			||||||
	const char *elf_path;
 | 
						const char *elf_path;
 | 
				
			||||||
 | 
						const char *output_section;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static error_t parse_opt(int key, char *arg, struct argp_state *state)
 | 
					static error_t parse_opt(int key, char *arg, struct argp_state *state)
 | 
				
			||||||
@@ -108,6 +104,9 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
 | 
				
			|||||||
		else if  (!strcmp(arg, "word"))
 | 
							else if  (!strcmp(arg, "word"))
 | 
				
			||||||
			args->granularity = GRANULARITY_32BIT;
 | 
								args->granularity = GRANULARITY_32BIT;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case 'O':
 | 
				
			||||||
 | 
							args->output_section = arg;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
	case ARGP_KEY_ARG:
 | 
						case ARGP_KEY_ARG:
 | 
				
			||||||
		if (state->arg_num >= 1)
 | 
							if (state->arg_num >= 1)
 | 
				
			||||||
			argp_usage(state);
 | 
								argp_usage(state);
 | 
				
			||||||
@@ -178,6 +177,7 @@ static void prepare_default_opts(struct command_line_options *opts)
 | 
				
			|||||||
	opts->list = false;
 | 
						opts->list = false;
 | 
				
			||||||
	opts->section_list = NULL;
 | 
						opts->section_list = NULL;
 | 
				
			||||||
	opts->elf_path = NULL;
 | 
						opts->elf_path = NULL;
 | 
				
			||||||
 | 
						opts->output_section = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void print_verbose_start_info(const struct command_line_options *cmd_opts)
 | 
					static void print_verbose_start_info(const struct command_line_options *cmd_opts)
 | 
				
			||||||
@@ -210,6 +210,10 @@ static void print_verbose_start_info(const struct command_line_options *cmd_opts
 | 
				
			|||||||
		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) {
 | 
				
			||||||
 | 
							print_debug("Output section: %s\n", cmd_opts->output_section);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cmd_opts->section_list) {
 | 
						if (cmd_opts->section_list) {
 | 
				
			||||||
		for (list_iter = cmd_opts->section_list, i = 1; list_iter; list_iter = sl_list_next(list_iter), i++) {
 | 
							for (list_iter = cmd_opts->section_list, i = 1; list_iter; list_iter = sl_list_next(list_iter), i++) {
 | 
				
			||||||
			print_debug("Input section [%d]: \"%s\"\n", i, (const char *)list_iter->data);
 | 
								print_debug("Input section [%d]: \"%s\"\n", i, (const char *)list_iter->data);
 | 
				
			||||||
@@ -342,6 +346,10 @@ int main(int argc, char **argv)
 | 
				
			|||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!cmd_opts.output_section) {
 | 
				
			||||||
 | 
							print_err("No output section specified. Will continue but not patch file.\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cmd_opts.list) {
 | 
						if (cmd_opts.list) {
 | 
				
			||||||
		list_predefined_crcs();
 | 
							list_predefined_crcs();
 | 
				
			||||||
		goto free_cmds;
 | 
							goto free_cmds;
 | 
				
			||||||
@@ -377,6 +385,15 @@ int main(int argc, char **argv)
 | 
				
			|||||||
		print_crcs(cmd_opts.section_list, crcs);
 | 
							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,
 | 
				
			||||||
 | 
										FORMAT_BARE, cmd_opts.little_endian)) {
 | 
				
			||||||
 | 
								ret = -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	elf_patch_close_and_free(ep);
 | 
						elf_patch_close_and_free(ep);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
free_cmds:
 | 
					free_cmds:
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user