/* $FreeBSD$ */ /*- * Copyright (c) 2013 Hans Petter Selasky. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * This utility sorts sysinit structure entries in binary format and * prints out the result in C-format. */ #include #include #include #include #include #include #include #include #include "sysinit.h" static int opt_R; static const char *input_f; static const char *output_f; static const char *struct_name; static const char *keyword; static struct sysinit_data **start; static struct sysinit_data **stop; static int input_file = -1; static int output_file = -1; static uint8_t *input_ptr; static uint32_t input_len; static uint32_t endian32; static char scratch_buf[4096]; static int success; static void do_sysinit(void); /* the following function converts the numbers into host endian format */ static uint32_t read32(uint32_t val) { uint32_t temp; uint32_t endian; endian = endian32; temp = 0; while (val) { temp |= (val & 0xF) << ((endian & 0xF) * 4); endian >>= 4; val >>= 4; } return (temp); } static void do_write(int fd, const char *buf) { int len = strlen(buf); if (write(fd, buf, len) != len) err(EX_SOFTWARE, "Could not write to output file"); } static void * do_malloc(int size) { void *ptr; ptr = malloc(size); if (ptr == NULL) errx(EX_SOFTWARE, "Could not allocate memory"); return (ptr); } static void usage(void) { errx(EX_USAGE, "sysinit -i sysinit.bin -o sysinit_data.c \\\n" "\t" "-k sysinit -s sysinit_data [ -R (reverse)]"); } static void cleanup(void) { if (output_file >= 0) close(output_file); if (input_file >= 0) close(input_file); if (success == 0) { if (output_f) unlink(output_f); } } static int compare(const void *_pa, const void *_pb) { const struct sysinit_data * const *pa = _pa; const struct sysinit_data * const *pb = _pb; if ((*pa)->dw_msb_value > (*pb)->dw_msb_value) return (1); if ((*pa)->dw_msb_value < (*pb)->dw_msb_value) return (-1); if ((*pa)->dw_lsb_value > (*pb)->dw_lsb_value) return (1); if ((*pa)->dw_lsb_value < (*pb)->dw_lsb_value) return (-1); return (0); /* equal */ } static int compare_R(const void *_pa, const void *_pb) { const struct sysinit_data * const *pa = _pa; const struct sysinit_data * const *pb = _pb; if ((*pa)->dw_msb_value > (*pb)->dw_msb_value) return (-1); if ((*pa)->dw_msb_value < (*pb)->dw_msb_value) return (1); if ((*pa)->dw_lsb_value > (*pb)->dw_lsb_value) return (-1); if ((*pa)->dw_lsb_value < (*pb)->dw_lsb_value) return (1); return (0); /* equal */ } int main(int argc, char **argv) { struct sysinit_data **sipp; int c; int entries; off_t off; while ((c = getopt(argc, argv, "k:s:i:o:Rh")) != -1) { switch (c) { case 'i': input_f = optarg; break; case 'o': output_f = optarg; break; case 'R': opt_R = 1; break; case 'k': keyword = optarg; break; case 's': struct_name = optarg; break; default: usage(); } } if (input_f == NULL || output_f == NULL || struct_name == NULL || keyword == NULL) usage(); atexit(&cleanup); cleanup(); input_file = open(input_f, O_RDONLY); if (input_file < 0) err(EX_SOFTWARE, "Could not open input file: %s", input_f); output_file = open(output_f, O_TRUNC | O_CREAT | O_RDWR, 0600); if (output_file < 0) err(EX_SOFTWARE, "Could not open output file: %s", output_f); off = lseek(input_file, 0, SEEK_END); input_ptr = do_malloc(off); input_len = off; if (input_len % (uint32_t)sizeof(struct sysinit_data)) { errx(EX_SOFTWARE, "Input file size is not divisible by %u", (unsigned int)sizeof(struct sysinit_data)); } off = lseek(input_file, 0, SEEK_SET); if (off < 0) err(EX_SOFTWARE, "Could not seek to start of input file"); if (read(input_file, input_ptr, input_len) != input_len) err(EX_SOFTWARE, "Could not read input file"); entries = input_len / (uint32_t)sizeof(struct sysinit_data); start = do_malloc(sizeof(void *) * entries); stop = start + entries; for (c = 0; c != entries; c++) start[c] = &((struct sysinit_data *)input_ptr)[c]; if (start != stop) endian32 = (*start)->dw_endian32; /* switch all fields to host endian order */ for (sipp = start; sipp < stop; sipp++) { (*sipp)->dw_lsb_value = read32((*sipp)->dw_lsb_value); (*sipp)->dw_msb_value = read32((*sipp)->dw_msb_value); (*sipp)->dw_file_line = read32((*sipp)->dw_file_line); } if (opt_R == 0) { /* sort entries, rising numerical order */ qsort(start, entries, sizeof(void *), &compare); } else { /* sort entries, falling numerical order */ qsort(start, entries, sizeof(void *), &compare_R); } /* safe all strings */ for (sipp = start; sipp < stop; sipp++) { (*sipp)->b_keyword_name[sizeof((*sipp)->b_keyword_name) - 1] = 0; (*sipp)->b_global_type[sizeof((*sipp)->b_global_type) - 1] = 0; (*sipp)->b_global_name[sizeof((*sipp)->b_global_name) - 1] = 0; (*sipp)->b_file_name[sizeof((*sipp)->b_file_name) - 1] = 0; (*sipp)->b_debug_info[sizeof((*sipp)->b_debug_info) - 1] = 0; } if (strcmp(keyword, "sysinit") == 0) do_sysinit(); else if (strcmp(keyword, "sysuninit") == 0) do_sysinit(); else errx(EX_USAGE, "Unknown keyword '%s'", keyword); success = 1; return (0); } static void do_sysinit(void) { struct sysinit_data **sipp; int c; snprintf(scratch_buf, sizeof(scratch_buf), "/*\n" " * This file was automatically generated.\n" " * Please do not edit.\n" " */\n\n"); /* write out externals */ for (c = 0, sipp = start; sipp < stop; c++, sipp++) { if (strcmp((const char *)(*sipp)->b_keyword_name, keyword)) continue; if ((*sipp)->dw_msb_value == 0) continue; snprintf(scratch_buf, sizeof(scratch_buf), "/* #%04u: %s entry at %s:%u */\n", c, (*sipp)->b_debug_info, (*sipp)->b_file_name, (unsigned int)(*sipp)->dw_file_line); do_write(output_file, scratch_buf); snprintf(scratch_buf, sizeof(scratch_buf), "extern %s %s;\n\n", (*sipp)->b_global_type, (*sipp)->b_global_name); do_write(output_file, scratch_buf); } snprintf(scratch_buf, sizeof(scratch_buf), "const void *%s[] = {\n", struct_name); do_write(output_file, scratch_buf); /* write out actual table */ for (c = 0, sipp = start; sipp < stop; c++, sipp++) { if (strcmp((const char *)(*sipp)->b_keyword_name, keyword)) continue; if ((*sipp)->dw_msb_value == 0) continue; snprintf(scratch_buf, sizeof(scratch_buf), "\t&%s, /* #%04u */\n", (*sipp)->b_global_name, (unsigned int)c); do_write(output_file, scratch_buf); } snprintf(scratch_buf, sizeof(scratch_buf), "\t(const void *)0\n" "};\n"); do_write(output_file, scratch_buf); }