^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Parser/loader for IHEX formatted data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright © 2008 David Woodhouse <dwmw2@infradead.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright © 2005 Jan Harkes <jaharkes@cs.cmu.edu>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <stdint.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <arpa/inet.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <sys/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <sys/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <sys/mman.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <fcntl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define _GNU_SOURCE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <getopt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define ALIGN(x, a) __ALIGN_KERNEL((x), (a))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct ihex_binrec {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct ihex_binrec *next; /* not part of the real data structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) uint32_t addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) uint16_t len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) uint8_t data[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * nybble/hex are little helpers to parse hexadecimal numbers to a byte value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) **/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static uint8_t nybble(const uint8_t n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (n >= '0' && n <= '9') return n - '0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) else if (n >= 'A' && n <= 'F') return n - ('A' - 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) else if (n >= 'a' && n <= 'f') return n - ('a' - 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static uint8_t hex(const uint8_t *data, uint8_t *crc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) uint8_t val = (nybble(data[0]) << 4) | nybble(data[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) *crc += val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static int process_ihex(uint8_t *data, ssize_t size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) static void file_record(struct ihex_binrec *record);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static int output_records(int outfd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static int sort_records = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static int wide_records = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static int include_jump = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static int usage(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) fprintf(stderr, "ihex2fw: Convert ihex files into binary "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) "representation for use by Linux kernel\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) fprintf(stderr, "usage: ihex2fw [<options>] <src.HEX> <dst.fw>\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) fprintf(stderr, " -w: wide records (16-bit length)\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) fprintf(stderr, " -s: sort records by address\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) fprintf(stderr, " -j: include records for CS:IP/EIP address\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) int main(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) int infd, outfd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct stat st;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) uint8_t *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) int opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) while ((opt = getopt(argc, argv, "wsj")) != -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) switch (opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) case 'w':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) wide_records = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) case 's':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) sort_records = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) case 'j':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) include_jump = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return usage();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (optind + 2 != argc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return usage();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (!strcmp(argv[optind], "-"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) infd = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) infd = open(argv[optind], O_RDONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (infd == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) fprintf(stderr, "Failed to open source file: %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return usage();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (fstat(infd, &st)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) perror("stat");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, infd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (data == MAP_FAILED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) perror("mmap");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (!strcmp(argv[optind+1], "-"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) outfd = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) outfd = open(argv[optind+1], O_TRUNC|O_CREAT|O_WRONLY, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (outfd == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) fprintf(stderr, "Failed to open destination file: %s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return usage();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (process_ihex(data, st.st_size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return output_records(outfd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static int process_ihex(uint8_t *data, ssize_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct ihex_binrec *record;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) size_t record_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) uint32_t offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) uint32_t data32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) uint8_t type, crc = 0, crcbyte = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) int i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) int line = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) next_record:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /* search for the start of record character */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) while (i < size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (data[i] == '\n') line++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (data[i++] == ':') break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* Minimum record length would be about 10 characters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (i + 10 > size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) fprintf(stderr, "Can't find valid record at line %d\n", line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) len = hex(data + i, &crc); i += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (wide_records) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) len <<= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) len += hex(data + i, &crc); i += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) record_size = ALIGN(sizeof(*record) + len, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) record = malloc(record_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (!record) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) fprintf(stderr, "out of memory for records\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) memset(record, 0, record_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) record->len = len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /* now check if we have enough data to read everything */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if (i + 8 + (record->len * 2) > size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) fprintf(stderr, "Not enough data to read complete record at line %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) record->addr = hex(data + i, &crc) << 8; i += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) record->addr |= hex(data + i, &crc); i += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) type = hex(data + i, &crc); i += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) for (j = 0; j < record->len; j++, i += 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) record->data[j] = hex(data + i, &crc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) /* check CRC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) crcbyte = hex(data + i, &crc); i += 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (crc != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) fprintf(stderr, "CRC failure at line %d: got 0x%X, expected 0x%X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) line, crcbyte, (unsigned char)(crcbyte-crc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) /* Done reading the record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) /* old style EOF record? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (!record->len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) record->addr += offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) file_record(record);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) goto next_record;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) case 1: /* End-Of-File Record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (record->addr || record->len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) fprintf(stderr, "Bad EOF record (type 01) format at line %d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) case 2: /* Extended Segment Address Record (HEX86) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) case 4: /* Extended Linear Address Record (HEX386) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (record->addr || record->len != 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) fprintf(stderr, "Bad HEX86/HEX386 record (type %02X) at line %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) type, line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /* We shouldn't really be using the offset for HEX86 because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * the wraparound case is specified quite differently. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) offset = record->data[0] << 8 | record->data[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) offset <<= (type == 2 ? 4 : 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) goto next_record;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) case 3: /* Start Segment Address Record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) case 5: /* Start Linear Address Record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (record->addr || record->len != 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) fprintf(stderr, "Bad Start Address record (type %02X) at line %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) type, line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) memcpy(&data32, &record->data[0], sizeof(data32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) data32 = htonl(data32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) memcpy(&record->data[0], &data32, sizeof(data32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /* These records contain the CS/IP or EIP where execution
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * starts. If requested output this as a record. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (include_jump)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) file_record(record);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) goto next_record;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) fprintf(stderr, "Unknown record (type %02X)\n", type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) static struct ihex_binrec *records;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) static void file_record(struct ihex_binrec *record)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) struct ihex_binrec **p = &records;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) while ((*p) && (!sort_records || (*p)->addr < record->addr))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) p = &((*p)->next);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) record->next = *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) *p = record;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static uint16_t ihex_binrec_size(struct ihex_binrec *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return p->len + sizeof(p->addr) + sizeof(p->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static int output_records(int outfd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) unsigned char zeroes[6] = {0, 0, 0, 0, 0, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) struct ihex_binrec *p = records;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) while (p) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) uint16_t writelen = ALIGN(ihex_binrec_size(p), 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) p->addr = htonl(p->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) p->len = htons(p->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) if (write(outfd, &p->addr, writelen) != writelen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) p = p->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) /* EOF record is zero length, since we don't bother to represent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) the type field in the binary version */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (write(outfd, zeroes, 6) != 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }