1 /* $FreeBSD$ */ 2 /*- 3 * Copyright (c) 2013 Hans Petter Selasky. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /* 28 * This utility sorts sysinit structure entries in binary format and 29 * prints out the result in C-format. 30 */ 31 32 #include <stdio.h> 33 #include <stdint.h> 34 #include <stdlib.h> 35 #include <err.h> 36 #include <unistd.h> 37 #include <fcntl.h> 38 #include <string.h> 39 #include <sysexits.h> 40 #include "sysinit.h" 41 42 static int opt_R; 43 static const char *input_f; 44 static const char *output_f; 45 static const char *struct_name; 46 static const char *keyword; 47 static struct sysinit_data **start; 48 static struct sysinit_data **stop; 49 50 static int input_file = -1; 51 static int output_file = -1; 52 53 static uint8_t *input_ptr; 54 static uint32_t input_len; 55 56 static uint32_t endian32; 57 58 static char scratch_buf[4096]; 59 60 static int success; 61 62 static void do_sysinit(void); 63 64 /* the following function converts the numbers into host endian format */ 65 66 static uint32_t 67 read32(uint32_t val) 68 { 69 uint32_t temp; 70 uint32_t endian; 71 72 endian = endian32; 73 temp = 0; 74 75 while (val) { 76 temp |= (val & 0xF) << ((endian & 0xF) * 4); 77 endian >>= 4; 78 val >>= 4; 79 } 80 return (temp); 81 } 82 83 static void 84 do_write(int fd, const char *buf) 85 { 86 int len = strlen(buf); 87 88 if (write(fd, buf, len) != len) 89 err(EX_SOFTWARE, "Could not write to output file"); 90 } 91 92 static void * 93 do_malloc(int size) 94 { 95 void *ptr; 96 97 ptr = malloc(size); 98 if (ptr == NULL) 99 errx(EX_SOFTWARE, "Could not allocate memory"); 100 return (ptr); 101 } 102 103 static void 104 usage(void) 105 { 106 errx(EX_USAGE, "sysinit -i sysinit.bin -o sysinit_data.c \\\n" 107 "\t" "-k sysinit -s sysinit_data [ -R (reverse)]"); 108 } 109 110 static void 111 cleanup(void) 112 { 113 if (output_file >= 0) 114 close(output_file); 115 if (input_file >= 0) 116 close(input_file); 117 if (success == 0) { 118 if (output_f) 119 unlink(output_f); 120 } 121 } 122 123 static int 124 compare(const void *_pa, const void *_pb) 125 { 126 const struct sysinit_data * const *pa = _pa; 127 const struct sysinit_data * const *pb = _pb; 128 129 if ((*pa)->dw_msb_value > (*pb)->dw_msb_value) 130 return (1); 131 132 if ((*pa)->dw_msb_value < (*pb)->dw_msb_value) 133 return (-1); 134 135 if ((*pa)->dw_lsb_value > (*pb)->dw_lsb_value) 136 return (1); 137 138 if ((*pa)->dw_lsb_value < (*pb)->dw_lsb_value) 139 return (-1); 140 141 return (0); /* equal */ 142 } 143 144 static int 145 compare_R(const void *_pa, const void *_pb) 146 { 147 const struct sysinit_data * const *pa = _pa; 148 const struct sysinit_data * const *pb = _pb; 149 150 if ((*pa)->dw_msb_value > (*pb)->dw_msb_value) 151 return (-1); 152 153 if ((*pa)->dw_msb_value < (*pb)->dw_msb_value) 154 return (1); 155 156 if ((*pa)->dw_lsb_value > (*pb)->dw_lsb_value) 157 return (-1); 158 159 if ((*pa)->dw_lsb_value < (*pb)->dw_lsb_value) 160 return (1); 161 162 return (0); /* equal */ 163 } 164 165 int 166 main(int argc, char **argv) 167 { 168 struct sysinit_data **sipp; 169 int c; 170 int entries; 171 off_t off; 172 173 while ((c = getopt(argc, argv, "k:s:i:o:Rh")) != -1) { 174 switch (c) { 175 case 'i': 176 input_f = optarg; 177 break; 178 case 'o': 179 output_f = optarg; 180 break; 181 case 'R': 182 opt_R = 1; 183 break; 184 case 'k': 185 keyword = optarg; 186 break; 187 case 's': 188 struct_name = optarg; 189 break; 190 default: 191 usage(); 192 } 193 } 194 195 if (input_f == NULL || output_f == NULL || 196 struct_name == NULL || keyword == NULL) 197 usage(); 198 199 atexit(&cleanup); 200 201 cleanup(); 202 203 input_file = open(input_f, O_RDONLY); 204 if (input_file < 0) 205 err(EX_SOFTWARE, "Could not open input file: %s", input_f); 206 207 output_file = open(output_f, O_TRUNC | O_CREAT | O_RDWR, 0600); 208 if (output_file < 0) 209 err(EX_SOFTWARE, "Could not open output file: %s", output_f); 210 211 off = lseek(input_file, 0, SEEK_END); 212 213 input_ptr = do_malloc(off); 214 input_len = off; 215 216 if (input_len % (uint32_t)sizeof(struct sysinit_data)) { 217 errx(EX_SOFTWARE, "Input file size is not divisible by %u", 218 (unsigned int)sizeof(struct sysinit_data)); 219 } 220 off = lseek(input_file, 0, SEEK_SET); 221 if (off < 0) 222 err(EX_SOFTWARE, "Could not seek to start of input file"); 223 224 if (read(input_file, input_ptr, input_len) != input_len) 225 err(EX_SOFTWARE, "Could not read input file"); 226 227 entries = input_len / (uint32_t)sizeof(struct sysinit_data); 228 229 start = do_malloc(sizeof(void *) * entries); 230 stop = start + entries; 231 232 for (c = 0; c != entries; c++) 233 start[c] = &((struct sysinit_data *)input_ptr)[c]; 234 235 if (start != stop) 236 endian32 = (*start)->dw_endian32; 237 238 /* switch all fields to host endian order */ 239 for (sipp = start; sipp < stop; sipp++) { 240 (*sipp)->dw_lsb_value = read32((*sipp)->dw_lsb_value); 241 (*sipp)->dw_msb_value = read32((*sipp)->dw_msb_value); 242 (*sipp)->dw_file_line = read32((*sipp)->dw_file_line); 243 } 244 245 if (opt_R == 0) { 246 /* sort entries, rising numerical order */ 247 qsort(start, entries, sizeof(void *), &compare); 248 } else { 249 /* sort entries, falling numerical order */ 250 qsort(start, entries, sizeof(void *), &compare_R); 251 } 252 253 /* safe all strings */ 254 for (sipp = start; sipp < stop; sipp++) { 255 (*sipp)->b_keyword_name[sizeof((*sipp)->b_keyword_name) - 1] = 0; 256 (*sipp)->b_global_type[sizeof((*sipp)->b_global_type) - 1] = 0; 257 (*sipp)->b_global_name[sizeof((*sipp)->b_global_name) - 1] = 0; 258 (*sipp)->b_file_name[sizeof((*sipp)->b_file_name) - 1] = 0; 259 (*sipp)->b_debug_info[sizeof((*sipp)->b_debug_info) - 1] = 0; 260 } 261 262 if (strcmp(keyword, "sysinit") == 0) 263 do_sysinit(); 264 else if (strcmp(keyword, "sysuninit") == 0) 265 do_sysinit(); 266 else 267 errx(EX_USAGE, "Unknown keyword '%s'", keyword); 268 269 success = 1; 270 271 return (0); 272 } 273 274 static void 275 do_sysinit(void) 276 { 277 struct sysinit_data **sipp; 278 int c; 279 280 snprintf(scratch_buf, sizeof(scratch_buf), 281 "/*\n" 282 " * This file was automatically generated.\n" 283 " * Please do not edit.\n" 284 " */\n\n"); 285 286 /* write out externals */ 287 for (c = 0, sipp = start; sipp < stop; c++, sipp++) { 288 if (strcmp((const char *)(*sipp)->b_keyword_name, keyword)) 289 continue; 290 if ((*sipp)->dw_msb_value == 0) 291 continue; 292 293 snprintf(scratch_buf, sizeof(scratch_buf), 294 "/* #%04u: %s entry at %s:%u */\n", 295 c, (*sipp)->b_debug_info, (*sipp)->b_file_name, 296 (unsigned int)(*sipp)->dw_file_line); 297 298 do_write(output_file, scratch_buf); 299 300 snprintf(scratch_buf, sizeof(scratch_buf), 301 "extern %s %s;\n\n", (*sipp)->b_global_type, 302 (*sipp)->b_global_name); 303 304 do_write(output_file, scratch_buf); 305 } 306 307 snprintf(scratch_buf, sizeof(scratch_buf), 308 "const void *%s[] = {\n", struct_name); 309 310 do_write(output_file, scratch_buf); 311 312 /* write out actual table */ 313 for (c = 0, sipp = start; sipp < stop; c++, sipp++) { 314 if (strcmp((const char *)(*sipp)->b_keyword_name, keyword)) 315 continue; 316 if ((*sipp)->dw_msb_value == 0) 317 continue; 318 319 snprintf(scratch_buf, sizeof(scratch_buf), 320 "\t&%s, /* #%04u */\n", 321 (*sipp)->b_global_name, (unsigned int)c); 322 323 do_write(output_file, scratch_buf); 324 } 325 326 snprintf(scratch_buf, sizeof(scratch_buf), 327 "\t(const void *)0\n" 328 "};\n"); 329 330 do_write(output_file, scratch_buf); 331 } 332