Human68k CUI emulator with sound.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

xinfo.c 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include "cmdline.h"
  6. #include "md5.h"
  7. int opt_csv = 0;
  8. int opt_hexdump = 0;
  9. uint8_t safechar(uint8_t c) {
  10. return c >= 0x20 && c < 0x7f ? c : '.';
  11. }
  12. void hexdump(uint8_t *data, uint32_t base, uint32_t len) {
  13. for(int i = 0; i < len; i += 16) {
  14. printf("0x%08x: ", base + i);
  15. for(int j = 0; j < 16; j++) {
  16. if(i + j < len)
  17. printf("%02x ", data[i + j]);
  18. else
  19. printf(" ");
  20. }
  21. for(int j = 0; j < 16; j++) {
  22. if(i + j < len)
  23. printf("%c", safechar(data[i + j]));
  24. else
  25. printf(" ");
  26. }
  27. printf("\n");
  28. }
  29. }
  30. static void hexdump_csv(uint8_t *data, int len) {
  31. for(int i = 0; i < len; i++) {
  32. printf("%02x", data[i]);
  33. }
  34. }
  35. const char *load_mode_name(uint8_t mode) {
  36. const char *load_mode_names[3] = { "Normal", "Minimum block", "High address" };
  37. if(mode >= 0 && mode <= 2) return load_mode_names[mode];
  38. return "Unknown";
  39. }
  40. void xinfo(char *filename) {
  41. FILE *f = fopen(filename, "rb");
  42. if(!f) {
  43. perror(filename);
  44. return;
  45. }
  46. fseek(f, 0, SEEK_END);
  47. long o = ftell(f);
  48. fseek(f, 0, SEEK_SET);
  49. uint8_t *buf = malloc(o);
  50. if(!buf) {
  51. fprintf(stderr, "%s: Could not allocate %ld bytes\n", filename, o);
  52. goto err1;
  53. }
  54. if(fread(buf, o, 1, f) < 1) {
  55. fprintf(stderr, "%s: Could not read %lu bytes.\n", filename, o);
  56. goto err1;
  57. }
  58. if(buf[0] != 'H' && buf[1] != 'U') {
  59. fprintf(stderr, "%s: X file signature invalid, not \"HU\"\n", filename);
  60. goto err1;
  61. }
  62. #define READ_LONG(x) ((buf[x] << 24) | (buf[x + 1] << 16) | (buf[x + 2] << 8) | buf[x + 3])
  63. #define READ_SHORT(x) ((buf[x] << 8) | buf[x + 1])
  64. uint8_t load_mode = buf[3];
  65. uint32_t base_addr = READ_LONG(0x04);
  66. uint32_t entry_point = READ_LONG(0x08);
  67. uint32_t text_size = READ_LONG(0x0c);
  68. if(text_size > 0 && 0x40 + text_size > o) {
  69. fprintf(stderr, "%s: .text section size exceeds end of file.\n", filename);
  70. goto err1;
  71. }
  72. uint32_t data_size = READ_LONG(0x10);
  73. if(data_size > 0 && 0x40 + text_size + data_size > o) {
  74. fprintf(stderr, "%s: .data section size exceeds end of file.\n", filename);
  75. goto err1;
  76. }
  77. uint32_t bss_size = READ_LONG(0x14);
  78. uint32_t reloc_size = READ_LONG(0x18);
  79. if(reloc_size > 0 && 0x40 + text_size + data_size + reloc_size > o) {
  80. fprintf(stderr, "%s: Relocation data size exceeds end of file.\n", filename);
  81. goto err1;
  82. }
  83. uint32_t sym_table_size = READ_LONG(0x1c);
  84. if(sym_table_size > 0 && 0x40 + text_size + data_size + reloc_size + sym_table_size > o) {
  85. fprintf(stderr, "%s: Symbol table size exceeds end of file.\n", filename);
  86. goto err1;
  87. }
  88. uint32_t scd_line_num_table_size = READ_LONG(0x20);
  89. if(scd_line_num_table_size > 0 && 0x40 + text_size + data_size + reloc_size + sym_table_size + scd_line_num_table_size > o) {
  90. fprintf(stderr, "%s: SCD line number table size exceeds end of file.\n", filename);
  91. goto err1;
  92. }
  93. uint32_t scd_sym_table_size = READ_LONG(0x24);
  94. if(scd_sym_table_size > 0 && 0x40 + text_size + data_size + reloc_size + sym_table_size + scd_line_num_table_size + scd_sym_table_size > o) {
  95. fprintf(stderr, "%s: SCD symbol table size exceeds end of file.\n", filename);
  96. goto err1;
  97. }
  98. uint32_t scd_string_table_size = READ_LONG(0x28);
  99. if(scd_string_table_size > 0 && 0x40 + text_size + data_size + reloc_size + sym_table_size + scd_line_num_table_size + scd_sym_table_size + scd_string_table_size > o) {
  100. fprintf(stderr, "%s: SCD string table size exceeds end of file.\n", filename);
  101. goto err1;
  102. }
  103. uint32_t bound_pos = READ_LONG(0x3c);
  104. if(bound_pos && bound_pos >= o) {
  105. fprintf(stderr, "Bound module list position exceeds end of file.\n");
  106. goto err1;
  107. }
  108. struct md5_ctx ctx;
  109. md5_init_ctx(&ctx);
  110. md5_process_bytes(buf, o, &ctx);
  111. uint8_t md5buf[16];
  112. md5_finish_ctx(&ctx, md5buf);
  113. if(opt_csv) {
  114. printf("%s\t%lu", filename, o);
  115. // MD5
  116. printf("\t");
  117. for(int j = 0; j < 16; j++) {
  118. printf("%02x", md5buf[j]);
  119. }
  120. printf("\t%d\t%s", load_mode, load_mode_name(load_mode));
  121. printf("\t0x%08x\t0x%08x\t0x%08x\t0x%08x\t0x%08x\t0x%08x\t0x%08x", base_addr, entry_point, text_size, data_size, bss_size, reloc_size, sym_table_size);
  122. printf("\t0x%08x\t0x%08x\t0x%08x\t0x%08x", scd_line_num_table_size, scd_sym_table_size, scd_string_table_size, bound_pos);
  123. if(opt_hexdump) {
  124. printf("\t");
  125. hexdump_csv(buf, 0x40);
  126. printf("\t");
  127. hexdump_csv(buf + 0x40, text_size);
  128. printf("\t");
  129. hexdump_csv(buf + 0x40 + text_size, data_size);
  130. printf("\t");
  131. hexdump_csv(buf + 0x40 + text_size + data_size, reloc_size);
  132. }
  133. printf("\n");
  134. } else {
  135. printf("%s: %luB ", filename, o);
  136. for(int j = 0; j < 16; j++) {
  137. printf("%02x", md5buf[j]);
  138. }
  139. printf("\n");
  140. printf("Header:\n");
  141. if(opt_hexdump)
  142. hexdump(buf, 0, 0x40);
  143. printf(" Load mode: %s (%d)\n", load_mode_name(load_mode), load_mode);
  144. printf(" Base address: 0x%08x\n", base_addr);
  145. printf(" Entry point: 0x%08x\n", entry_point);
  146. printf(" Text section size: 0x%08x (%dB)\n", text_size, text_size);
  147. printf(" Data section size: 0x%08x (%dB)\n", data_size, data_size);
  148. printf(" BSS size: 0x%08x (%dB)\n", bss_size, bss_size);
  149. printf(" Relocation table size: 0x%08x (%dB)\n", reloc_size, reloc_size);
  150. printf(" Symbol table size: 0x%08x (%dB)\n", sym_table_size, sym_table_size);
  151. printf(" SCD line number table size: 0x%08x (%dB)\n", scd_line_num_table_size, scd_line_num_table_size);
  152. printf(" SCD symbol table size: 0x%08x (%dB)\n", scd_sym_table_size, scd_sym_table_size);
  153. printf(" SCD string table size: 0x%08x (%dB)\n", scd_string_table_size, scd_string_table_size);
  154. printf(" Bound module list: 0x%08x\n", bound_pos);
  155. if(opt_hexdump) {
  156. printf(".text (%dB):\n", text_size);
  157. if(0x40 + text_size > o) {
  158. hexdump(buf + 0x40, 0x40, o - 0x40);
  159. } else {
  160. hexdump(buf + 0x40, 0x40, text_size);
  161. }
  162. printf(".data (%dB):\n", data_size);
  163. if(0x40 + text_size + data_size > o) {
  164. hexdump(buf + 0x40 + text_size, 0x40 + text_size, o - (0x40 + text_size));
  165. } else {
  166. hexdump(buf + 0x40 + text_size, 0x40 + text_size, data_size);
  167. }
  168. printf("Relocation (%dB):\n", reloc_size);
  169. if(0x40 + text_size + data_size + reloc_size > o) {
  170. hexdump(buf + 0x40 + text_size + data_size, 0x40 + text_size + data_size, o - (0x40 + text_size + data_size));
  171. } else {
  172. hexdump(buf + 0x40 + text_size + data_size, 0x40 + text_size + data_size, reloc_size);
  173. }
  174. }
  175. if(reloc_size > 0) {
  176. printf("Relocation:\n");
  177. uint32_t text_loc = 0x40;
  178. for(int i = 0; i < reloc_size; i+=2) {
  179. uint32_t r = READ_SHORT(0x40 + text_size + data_size + i);
  180. if(r == 1) {
  181. i += 2;
  182. r = READ_LONG(0x40 + text_size + data_size + i);
  183. i += 2; // 4 total, with `for' increment
  184. }
  185. text_loc += r & 0xfffffffe;
  186. if(text_loc >= 0x40 + text_size) {
  187. fprintf(stderr, "%s: Relocation out of bounds.\n", filename);
  188. break;
  189. } else {
  190. if(r & 1) {
  191. printf(" @%04x: %04x -> %08x (%04x)\n", i, r, text_loc, READ_SHORT(text_loc));
  192. } else {
  193. printf(" @%04x: %04x -> %08x (%08x)\n", i, r, text_loc, READ_LONG(text_loc));
  194. }
  195. }
  196. }
  197. }
  198. if(bound_pos > 0) {
  199. printf("Bound modules:\n");
  200. char fname[32];
  201. for(int i = bound_pos; i < o; i += 0x20) {
  202. memset(fname, 0, sizeof(fname) / sizeof(fname[0]));
  203. int f = 0;
  204. for(int j = i; j < i + 8; j++) {
  205. if(buf[j] > 0x20) fname[f++] = buf[j];
  206. }
  207. fname[f++] = '.';
  208. for(int j = i + 8; j < i + 8 + 3; j++) {
  209. if(buf[j] > 0x20) fname[f++] = buf[j];
  210. }
  211. uint32_t next_pos = i + 0x40 > o ? bound_pos : READ_LONG(i + 0x20 + 0x1C);
  212. uint32_t module_pos = READ_LONG(i + 0x1C);
  213. printf("%-12s %c%c%c%c @0x%08x % 6d ", fname, buf[i+11] & 0x20 ? 'A' : '-', buf[i+11] & 0x40 ? 'S' : '-', buf[i+11] & 0x02 ? 'H' : '-', buf[i+11] & 0x01 ? 'R' : '-', module_pos, next_pos - module_pos);
  214. printf("%04d-%02d-%02d %d:%02d:%02d\n", 1980 + ((buf[i+0x19] >> 1) & 0x7f), ((buf[i+0x19] & 0x01) << 3) | (buf[i+0x18] >> 5), buf[i+0x18] & 0x1f, buf[i+0x17] >> 3, ((buf[i+0x17] & 0x07) << 3) | (buf[i + 0x16] >> 5), (buf[i+0x16] & 0x1f) << 1);
  215. }
  216. }
  217. }
  218. err1:
  219. free(buf);
  220. fclose(f);
  221. }
  222. int main(int argc, char **argv) {
  223. int optind = cmdline_parse_args(argc, argv, (struct cmdline_option[]){
  224. {
  225. 'c', "csv",
  226. "CSV format mode",
  227. 0,
  228. TYPE_SWITCH,
  229. TYPE_INT, &opt_csv
  230. },
  231. {
  232. 'x', "hexdump",
  233. "Dump data as hex",
  234. 0,
  235. TYPE_SWITCH,
  236. TYPE_INT, &opt_hexdump
  237. },
  238. CMDLINE_ARG_TERMINATOR
  239. }, 1, 0, "<file.x> [<file.x> ...]");
  240. if(optind < 0) exit(-optind);
  241. if(opt_csv) {
  242. printf(
  243. "File"
  244. "\tSize"
  245. "\tMD5"
  246. "\tLoad mode"
  247. "\tLoad mode name"
  248. "\tBase addr"
  249. "\tEntry point"
  250. "\tText size"
  251. "\tData size"
  252. "\tBSS size"
  253. "\tReloc size"
  254. "\tSym table size"
  255. "\tSCD line num table size"
  256. "\tSCD sym table size"
  257. "\tSCD string table size"
  258. "\tBound module pos"
  259. );
  260. if(opt_hexdump)
  261. printf("\tHeader\t.text\t.data\tReloc data");
  262. printf("\n");
  263. }
  264. for(int i = optind; i < argc; i++) {
  265. xinfo(argv[i]);
  266. }
  267. return 0;
  268. }