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