2b63d400d9b7407b2da6ef955a5a2c46baf861e8
7 // (C) 2010 Underground Software
9 // JLH = James Hammons <jlhamm@acm.org>
10 // JPM = Jean-Paul Mari <djipi.mari@gmail.com>
13 // --- ---------- ------------------------------------------------------------
14 // JLH 01/16/2010 Created this log ;-)
15 // JLH 02/28/2010 Added functions to look inside .ZIP files and handle
17 // JLH 06/01/2012 Added function to check ZIP file CRCs against file DB
18 // JPM 06/06/2016 Visual Studio support
19 // JPM 06/15/2016 ELF format support
20 // JPM 06/19/2016 Soft debugger support
21 // JPM 07/15/2016 DWARF format support
26 #include "_MSC_VER/config.h"
36 #include "universalhdr.h"
39 #include "libelf/libelf.h"
40 #include "libelf/gelf.h"
42 #include "debugger/ELFManager.h"
43 #include "debugger/DBGManager.h"
46 // Private function prototypes
48 static int gzfilelength(gzFile gd
);
49 //#if defined(_MSC_VER) || defined(__MINGW64__)|| defined(__MINGW32__) || defined(__CYGWIN__)
50 static bool CheckExtension(const uint8_t *filename
, const char *ext
);
52 //static bool CheckExtension(const char * filename, const char * ext);
54 //static int ParseFileType(uint8_t header1, uint8_t header2, uint32_t size);
56 // Private variables/enums
60 // Generic ROM loading
62 uint32_t JaguarLoadROM(uint8_t * &rom
, char * path
)
64 // We really should have some kind of sanity checking for the ROM size here to prevent
65 // a buffer overflow... !!! FIX !!!
67 #pragma message("Warning: !!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!")
69 #warning "!!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!"
73 WriteLog("FILE: JaguarLoadROM attempting to load file '%s'...", path
);
74 char * ext
= strrchr(path
, '.');
76 // No filename extension == YUO FAIL IT (it is loading the file).
77 // This is naive, but it works. But should probably come up with something a little
78 // more robust, to prevent problems with dopes trying to exploit this.
81 WriteLog("FAILED!\n");
85 WriteLog("\nFILE: Succeeded in finding extension (%s)!\n", ext
);
86 WriteLog("FILE: Loading \"%s\"...", path
);
88 if (strcasecmp(ext
, ".zip") == 0)
90 // Handle ZIP file loading here...
91 WriteLog("(ZIPped)...");
93 // uint8_t * buffer = NULL;
94 // romSize = GetFileFromZIP(path, FT_SOFTWARE, buffer);
95 romSize
= GetFileFromZIP(path
, FT_SOFTWARE
, rom
);
99 WriteLog("Failed!\n");
103 // memcpy(rom, buffer, romSize);
108 // Handle gzipped files transparently [Adam Green]...
110 gzFile fp
= gzopen(path
, "rb");
114 WriteLog("Failed!\n");
118 romSize
= gzfilelength(fp
);
119 rom
= new uint8_t[romSize
];
120 gzseek(fp
, 0, SEEK_SET
);
121 gzread(fp
, rom
, romSize
);
125 WriteLog("OK (%i bytes)\n", romSize
);
132 // Jaguar file loading
133 // We do a more intelligent file analysis here instead of relying on (possible
134 // false) file extensions which people don't seem to give two shits about
137 bool JaguarLoadFile(char * path
)
140 GElf_Ehdr ElfEhdr
, *PtrGElfEhdr
;
142 Elf_Data
*PtrElfData
;
143 GElf_Shdr GElfShdr
, *PtrGElfShdr
;
145 uint8_t *buffer
= NULL
;
147 size_t ElfSectionNameType
;
148 int DBGType
= DBG_NO_TYPE
;
152 jaguarROMSize
= JaguarLoadROM(buffer
, path
);
154 if (jaguarROMSize
== 0)
156 // It's up to the GUI to report errors, not us. :-)
157 WriteLog("FILE: Could not load ROM from file \"%s\"...\nAborting load!\n", path
);
161 jaguarMainROMCRC32
= crc32_calcCheckSum(buffer
, jaguarROMSize
);
162 WriteLog("CRC: %08X\n", (unsigned int)jaguarMainROMCRC32
);
163 // TODO: Check for EEPROM file in ZIP file. If there is no EEPROM in the user's EEPROM
164 // directory, copy the one from the ZIP file, if it exists.
166 jaguarRunAddress
= 0x802000; // For non-BIOS runs, this is true
167 int fileType
= ParseFileType(buffer
, jaguarROMSize
);
168 jaguarCartInserted
= false;
171 if (fileType
== JST_ROM
)
173 jaguarCartInserted
= true;
174 memcpy(jagMemSpace
+ 0x800000, buffer
, jaguarROMSize
);
175 // Checking something...
176 jaguarRunAddress
= GET32(jagMemSpace
, 0x800404);
177 WriteLog("FILE: Cartridge run address is reported as $%X...\n", jaguarRunAddress
);
181 else if (fileType
== JST_ALPINE
)
183 // File extension ".ROM": Alpine image that loads/runs at $802000
184 WriteLog("FILE: Setting up Alpine ROM... Run address: 00802000, length: %08X\n", jaguarROMSize
);
185 memset(jagMemSpace
+ 0x800000, 0xFF, 0x2000);
186 memcpy(jagMemSpace
+ 0x802000, buffer
, jaguarROMSize
);
189 // Maybe instead of this, we could try requiring the STUBULATOR ROM? Just a thought...
190 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
191 // This kludge works! Yeah!
192 SET32(jaguarMainRAM
, 0x10, 0x00001000);
193 SET16(jaguarMainRAM
, 0x1000, 0x60FE); // Here: bra Here
196 else if (fileType
== JST_ELF32
)
200 char *PtrELFExe
= (char *)ELFManager_ExeCopy(buffer
, jaguarROMSize
);
202 if (PtrELFExe
!= NULL
)
204 if ((elf_version(EV_CURRENT
) != EV_NONE
) && (ElfMem
= ELFManager_MemOpen(PtrELFExe
, jaguarROMSize
)))
206 if (ELFManager_DwarfInit(ElfMem
))
208 DBGType
|= DBG_ELFDWARF
;
211 if (!elf_getshdrnum(ElfMem
, &NbrSect
))
213 if (((PtrGElfEhdr
= gelf_getehdr(ElfMem
, &ElfEhdr
)) != NULL
) && ((PtrElfScn
= elf_getscn(ElfMem
, 0)) != NULL
))
215 for (error
= false; (PtrElfScn
!= NULL
) && (error
== false); PtrElfScn
= elf_nextscn(ElfMem
, PtrElfScn
))
219 if ((PtrGElfShdr
= gelf_getshdr(PtrElfScn
, &GElfShdr
)) == NULL
)
225 NameSection
= elf_strptr(ElfMem
, PtrGElfEhdr
->e_shstrndx
, (size_t)PtrGElfShdr
->sh_name
);
226 WriteLog("FILE: ELF Section name: %s\n", NameSection
);
228 if ((ElfSectionNameType
= ELFManager_GetSectionType(NameSection
)) == ELF_NO_TYPE
)
230 WriteLog("FILE: ELF Section not listed\n");
235 switch (PtrGElfShdr
->sh_type
)
241 if ((PtrGElfShdr
->sh_flags
& (SHF_ALLOC
| SHF_WRITE
| SHF_EXECINSTR
)))
243 if (PtrGElfShdr
->sh_addr
>= 0x800000)
245 memcpy(jagMemSpace
+ PtrGElfShdr
->sh_addr
, buffer
+ PtrGElfShdr
->sh_offset
, PtrGElfShdr
->sh_size
);
250 memcpy(jaguarMainRAM
+ PtrGElfShdr
->sh_addr
, buffer
+ PtrGElfShdr
->sh_offset
, PtrGElfShdr
->sh_size
);
255 switch (ElfSectionNameType
)
257 case ELF_debug_aranges_TYPE
:
258 case ELF_debug_info_TYPE
:
259 case ELF_debug_abbrev_TYPE
:
260 case ELF_debug_line_TYPE
:
261 case ELF_debug_frame_TYPE
:
262 case ELF_debug_ranges_TYPE
:
263 case ELF_debug_str_TYPE
:
264 case ELF_debug_loc_TYPE
:
267 case ELF_comment_TYPE
:
282 while ((error
== false) && ((PtrElfData
= elf_getdata(PtrElfScn
, PtrElfData
)) != NULL
))
284 if (!ELFManager_AddTab(PtrElfData
, ElfSectionNameType
))
299 jaguarRunAddress
= (uint32_t)PtrGElfEhdr
->e_entry
;
300 WriteLog("FILE: Setting up ELF 32bits... Run address: %08X\n", jaguarRunAddress
);
315 WriteLog("FILE: libelf version is not recognized or libelf memory cannot be opened\n");
321 WriteLog("FILE: ELFManager cannot allocate memory\n");
328 WriteLog("FILE: ELF parsing error\n");
330 if ((err
= elf_errno()))
332 WriteLog("FILE: ELF error: %s\n", elf_errmsg(err
));
339 DBGManager_SetType(DBGType
);
343 else if (fileType
== JST_ABS_TYPE1
)
345 // For ABS type 1, run address == load address
346 uint32_t loadAddress
= GET32(buffer
, 0x16),
347 codeSize
= GET32(buffer
, 0x02) + GET32(buffer
, 0x06);
348 WriteLog("FILE: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress
, codeSize
);
349 memcpy(jagMemSpace
+ loadAddress
, buffer
+ 0x24, codeSize
);
351 jaguarRunAddress
= loadAddress
;
354 else if (fileType
== JST_ABS_TYPE2
)
356 uint32_t loadAddress
= GET32(buffer
, 0x28), runAddress
= GET32(buffer
, 0x24),
357 codeSize
= GET32(buffer
, 0x18) + GET32(buffer
, 0x1C);
358 WriteLog("FILE: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress
, codeSize
);
359 memcpy(jagMemSpace
+ loadAddress
, buffer
+ 0xA8, codeSize
);
361 jaguarRunAddress
= runAddress
;
364 // NB: This is *wrong*
366 Basically, if there is no "JAG" at position $1C, then the long there is the load/start
367 address in LITTLE ENDIAN.
368 If "JAG" is present, the the next character ("R" or "L") determines the size of the
369 JagServer command (2 bytes vs. 4). Following that are the commands themselves;
370 typically it will either be 2 (load) or 3 (load & run). Command headers go like so:
389 10: (Poll for commands)
391 12: (Load & run user program)
392 filname, terminated with NULL
397 else if (fileType
== JST_JAGSERVER
)
399 // This kind of shiaut should be in the detection code below...
400 // (and now it is! :-)
401 // if (buffer[0x1C] == 'J' && buffer[0x1D] == 'A' && buffer[0x1E] == 'G')
403 // Still need to do some checking here for type 2 vs. type 3. This assumes 3
404 // Also, JAGR vs. JAGL (word command size vs. long command size)
405 uint32_t loadAddress
= GET32(buffer
, 0x22), runAddress
= GET32(buffer
, 0x2A);
406 WriteLog("FILE: Setting up homebrew (Jag Server)... Run address: $%X, length: $%X\n", runAddress
, jaguarROMSize
- 0x2E);
407 memcpy(jagMemSpace
+ loadAddress
, buffer
+ 0x2E, jaguarROMSize
- 0x2E);
409 jaguarRunAddress
= runAddress
;
411 // Hmm. Is this kludge necessary?
412 SET32(jaguarMainRAM
, 0x10, 0x00001000); // Set Exception #4 (Illegal Instruction)
413 SET16(jaguarMainRAM
, 0x1000, 0x60FE); // Here: bra Here
417 // else // Special WTFOMGBBQ type here...
419 // uint32_t loadAddress = (buffer[0x1F] << 24) | (buffer[0x1E] << 16) | (buffer[0x1D] << 8) | buffer[0x1C];
420 // WriteLog("FILE: Setting up homebrew (GEMDOS WTFOMGBBQ type)... Run address: $%X, length: $%X\n", loadAddress, jaguarROMSize - 0x20);
421 // memcpy(jagMemSpace + loadAddress, buffer + 0x20, jaguarROMSize - 0x20);
423 // jaguarRunAddress = loadAddress;
427 else if (fileType
== JST_WTFOMGBBQ
)
429 uint32_t loadAddress
= (buffer
[0x1F] << 24) | (buffer
[0x1E] << 16) | (buffer
[0x1D] << 8) | buffer
[0x1C];
430 WriteLog("FILE: Setting up homebrew (GEMDOS WTFOMGBBQ type)... Run address: $%X, length: $%X\n", loadAddress
, jaguarROMSize
- 0x20);
431 memcpy(jagMemSpace
+ loadAddress
, buffer
+ 0x20, jaguarROMSize
- 0x20);
433 jaguarRunAddress
= loadAddress
;
437 // We can assume we have JST_NONE at this point. :-P
438 WriteLog("FILE: Failed to load headerless file.\n");
444 // "Debugger" file loading
445 // To keep the things separate between "Debugger" and "Alpine" loading until usage clarification has been done
447 bool DebuggerLoadFile(char * path
)
449 return (AlpineLoadFile(path
));
454 // "Alpine" file loading
455 // Since the developers were coming after us with torches and pitchforks, we
456 // decided to allow this kind of thing. ;-) But ONLY FOR THE DEVS, DAMMIT! >:-U
459 bool AlpineLoadFile(char * path
)
461 uint8_t * buffer
= NULL
;
462 jaguarROMSize
= JaguarLoadROM(buffer
, path
);
464 if (jaguarROMSize
== 0)
466 // It's up to the GUI to deal with failure, not us. ;-)
467 WriteLog("FILE: Could not load Alpine from file \"%s\"...\nAborting load!\n", path
);
471 jaguarMainROMCRC32
= crc32_calcCheckSum(buffer
, jaguarROMSize
);
472 WriteLog("FILE: CRC is %08X\n", (unsigned int)jaguarMainROMCRC32
);
475 jaguarRunAddress
= 0x802000;
477 WriteLog("FILE: Setting up Alpine ROM with non-standard length... Run address: 00802000, length: %08X\n", jaguarROMSize
);
479 memset(jagMemSpace
+ 0x800000, 0xFF, 0x2000);
480 memcpy(jagMemSpace
+ 0x802000, buffer
, jaguarROMSize
);
483 // Maybe instead of this, we could try requiring the STUBULATOR ROM? Just a thought...
484 // Try setting the vector to say, $1000 and putting an instruction there
485 // that loops forever:
486 // This kludge works! Yeah!
487 SET32(jaguarMainRAM
, 0x10, 0x00001000); // Set Exception #4 (Illegal Instruction)
488 SET16(jaguarMainRAM
, 0x1000, 0x60FE); // Here: bra Here
495 // Get the length of a (possibly) gzipped file
497 static int gzfilelength(gzFile gd
)
499 int size
= 0, length
= 0;
500 unsigned char buffer
[0x10000];
506 // Read in chunks until EOF
507 size
= gzread(gd
, buffer
, 0x10000);
522 // Compare extension to passed in filename. If equal, return true; otherwise false.
524 //#if defined(_MSC_VER) || defined(__MINGW64__)|| defined(__MINGW32__) || defined(__CYGWIN__)
525 static bool CheckExtension(const uint8_t *filename
, const char *ext
)
527 //static bool CheckExtension(const char * filename, const char * ext)
530 // Sanity checking...
531 if ((filename
== NULL
) || (ext
== NULL
))
534 const char * filenameExt
= strrchr((const char *)filename
, '.'); // Get the file's extension (if any)
536 if (filenameExt
== NULL
)
539 return (strcasecmp(filenameExt
, ext
) == 0 ? true : false);
544 // Get file from .ZIP
545 // Returns the size of the file inside the .ZIP file that we're looking at
546 // NOTE: If the thing we're looking for is found, it allocates it in the passed in buffer.
547 // Which means we have to deallocate it later.
549 uint32_t GetFileFromZIP(const char * zipFile
, FileType type
, uint8_t * &buffer
)
551 // NOTE: We could easily check for this by discarding anything that's larger than the RAM/ROM
552 // size of the Jaguar console.
553 #if defined(_MSC_VER)
554 #pragma message("Warning: !!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!")
556 #warning "!!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!"
558 const char ftStrings
[5][32] = { "Software", "EEPROM", "Label", "Box Art", "Controller Overlay" };
559 // ZIP * zip = openzip(0, 0, zipFile);
560 FILE * zip
= fopen(zipFile
, "rb");
564 WriteLog("FILE: Could not open file '%s'!\n", zipFile
);
572 // The order is here is important: If the file is found, we need to short-circuit the
573 // readzip() call because otherwise, 'ze' will be pointing to the wrong file!
574 // while (!found && readzip(zip))
575 while (!found
&& GetZIPHeader(zip
, ze
))
579 // Here we simply rely on the file extension to tell the truth, but we know
580 // that extensions lie like sons-a-bitches. So this is naive, we need to do
581 // something a little more robust to keep bad things from happening here.
582 #if defined(_MSC_VER)
583 #pragma message("Warning: !!! Checking for image by extension can be fooled !!!")
585 #warning "!!! Checking for image by extension can be fooled !!!"
587 if ((type
== FT_LABEL
) && (CheckExtension(ze
.filename
, ".png") || CheckExtension(ze
.filename
, ".jpg") || CheckExtension(ze
.filename
, ".gif")))
590 WriteLog("FILE: Found image file '%s'.\n", ze
.filename
);
593 if ((type
== FT_SOFTWARE
) && (CheckExtension(ze
.filename
, ".j64")
594 || CheckExtension(ze
.filename
, ".rom") || CheckExtension(ze
.filename
, ".abs")
595 || CheckExtension(ze
.filename
, ".cof") || CheckExtension(ze
.filename
, ".coff")
596 || CheckExtension(ze
.filename
, ".jag") || CheckExtension(ze
.filename
, ".elf")))
599 WriteLog("FILE: Found software file '%s'.\n", ze
.filename
);
602 if ((type
== FT_EEPROM
) && (CheckExtension(ze
.filename
, ".eep") || CheckExtension(ze
.filename
, ".eeprom")))
605 WriteLog("FILE: Found EEPROM file '%s'.\n", ze
.filename
);
609 fseek(zip
, ze
.compressedSize
, SEEK_CUR
);
612 uint32_t fileSize
= 0;
616 WriteLog("FILE: Uncompressing...");
617 // Insert file size sanity check here...
618 buffer
= new uint8_t[ze
.uncompressedSize
];
620 // if (readuncompresszip(zip, ze.compressedSize, buffer) == 0)
621 // if (UncompressFileFromZIP(zip, ze.compressedSize, buffer) == 0)
622 if (UncompressFileFromZIP(zip
, ze
, buffer
) == 0)
624 fileSize
= ze
.uncompressedSize
;
625 WriteLog("success! (%u bytes)\n", fileSize
);
631 WriteLog("FAILED!\n");
635 // Didn't find what we're looking for...
636 WriteLog("FILE: Failed to find file of type %s...\n", ftStrings
[type
]);
644 uint32_t GetFileDBIdentityFromZIP(const char * zipFile
)
646 FILE * zip
= fopen(zipFile
, "rb");
650 WriteLog("FILE: Could not open file '%s'!\n", zipFile
);
656 // Loop through all files in the zip file under consideration
657 while (GetZIPHeader(zip
, ze
))
659 // & loop through all known CRC32s in our file DB to see if it's there!
662 while (romList
[index
].crc32
!= 0xFFFFFF)
664 if (romList
[index
].crc32
== ze
.crc32
)
673 // We didn't find it, so skip the compressed data...
674 fseek(zip
, ze
.compressedSize
, SEEK_CUR
);
678 return (uint32_t )-1;
682 bool FindFileInZIPWithCRC32(const char * zipFile
, uint32_t crc
)
684 FILE * zip
= fopen(zipFile
, "rb");
688 WriteLog("FILE: Could not open file '%s'!\n", zipFile
);
694 // Loop through all files in the zip file under consideration
695 while (GetZIPHeader(zip
, ze
))
703 fseek(zip
, ze
.compressedSize
, SEEK_CUR
);
712 // Parse the file type based upon file size and/or headers.
714 uint32_t ParseFileType(uint8_t * buffer
, uint32_t size
)
716 // Check headers first...
719 if (buffer
[EI_CLASS
] == ELFCLASS32
)
721 if (((BigToLittleEndian16(((Elf32_Ehdr
*)buffer
)->e_machine
) & 0xFF) == EM_68K
) && (BigToLittleEndian16(((Elf32_Ehdr
*)buffer
)->e_type
) == ET_EXEC
) && (buffer
[0] == ELFMAG0
) && (buffer
[1] == ELFMAG1
) && (buffer
[2] == ELFMAG2
) && (buffer
[3] == ELFMAG3
))
726 if (buffer
[0] == 0x60 && buffer
[1] == 0x1B)
727 return JST_ABS_TYPE1
;
730 if (buffer
[0] == 0x01 && buffer
[1] == 0x50)
731 return JST_ABS_TYPE2
;
733 // Jag Server & other old shite
734 if (buffer
[0] == 0x60 && buffer
[1] == 0x1A)
736 if (buffer
[0x1C] == 'J' && buffer
[0x1D] == 'A' && buffer
[0x1E] == 'G')
737 return JST_JAGSERVER
;
739 return JST_WTFOMGBBQ
;
742 // And if that fails, try file sizes...
744 // If the file size is divisible by 1M, we probably have an regular ROM.
745 // We can also check our CRC32 against the internal ROM database to be sure.
746 // (We also check for the Memory Track cartridge size here as well...)
747 if ((size
% 1048576) == 0 || size
== 131072)
750 // If the file size + 8192 bytes is divisible by 1M, we probably have an
751 // Alpine format ROM.
752 if (((size
+ 8192) % 1048576) == 0)
760 // Check for universal header
762 bool HasUniversalHeader(uint8_t * rom
, uint32_t romSize
)
768 for(int i
=0; i
<8192; i
++)
769 if (rom
[i
] != universalCartHeader
[i
])
779 Stubulator ROM vectors...
780 handler 001 at $00E00008
781 handler 002 at $00E008DE
782 handler 003 at $00E008E2
783 handler 004 at $00E008E6
784 handler 005 at $00E008EA
785 handler 006 at $00E008EE
786 handler 007 at $00E008F2
787 handler 008 at $00E0054A
788 handler 009 at $00E008FA
789 handler 010 at $00000000
790 handler 011 at $00000000
791 handler 012 at $00E008FE
792 handler 013 at $00E00902
793 handler 014 at $00E00906
794 handler 015 at $00E0090A
795 handler 016 at $00E0090E
796 handler 017 at $00E00912
797 handler 018 at $00E00916
798 handler 019 at $00E0091A
799 handler 020 at $00E0091E
800 handler 021 at $00E00922
801 handler 022 at $00E00926
802 handler 023 at $00E0092A
803 handler 024 at $00E0092E
804 handler 025 at $00E0107A
805 handler 026 at $00E0107A
806 handler 027 at $00E0107A
807 handler 028 at $00E008DA
808 handler 029 at $00E0107A
809 handler 030 at $00E0107A
810 handler 031 at $00E0107A
811 handler 032 at $00000000
813 Let's try setting up the illegal instruction vector for a stubulated jaguar...
815 SET32(jaguar_mainRam, 0x08, 0x00E008DE);
816 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
817 SET32(jaguar_mainRam, 0x10, 0x00E008E6); // <-- Should be here (it is)...
818 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
821 ABS Format sleuthing (LBUGDEMO.ABS):
823 000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
824 000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
827 DRI-format file detected...
828 Text segment size = 0x0000050c bytes
829 Data segment size = 0x000462c0 bytes
830 BSS Segment size = 0x00000428 bytes
831 Symbol Table size = 0x000012a6 bytes
832 Absolute Address for text segment = 0x00802000
833 Absolute Address for data segment = 0x0080250c
834 Absolute Address for BSS segment = 0x00004000
837 000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
838 000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
839 000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
841 000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
842 000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
843 000050 00 00 00 00 00 00 00 20
844 000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
845 000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
846 000078 00 00 00 00 00 00 00 40
847 000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
848 000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
849 0000a0 00 00 00 00 00 00 00 80
851 Header size is $A8 bytes...
853 BSD/COFF format file detected...
855 Symbol Table offset = 230160 ($00038310)
856 Symbol Table contains 1339 symbol entries ($0000053B)
857 The additional header size is 28 bytes ($001C)
858 Magic Number for RUN_HDR = 0x00000107
859 Text Segment Size = 7632 ($00001DD0)
860 Data Segment Size = 222360 ($00036498)
861 BSS Segment Size = 428928 ($00068B80)
862 Starting Address for executable = 0x00802000
863 Start of Text Segment = 0x00802000
864 Start of Data Segment = 0x00803dd0
873 // (C) 2010 Underground Software
875 // JLH = James Hammons <jlhamm@acm.org>
876 // JPM = Jean-Paul Mari <djipi.mari@gmail.com>
879 // --- ---------- ------------------------------------------------------------
880 // JLH 01/16/2010 Created this log ;-)
881 // JLH 02/28/2010 Added functions to look inside .ZIP files and handle
883 // JLH 06/01/2012 Added function to check ZIP file CRCs against file DB
884 // JPM 06/06/2016 Visual Studio support
885 // JPM 06/15/2016 ELF format support
886 // JPM 06/19/2016 Soft debugger support
887 // JPM 07/15/2016 DWARF format support
891 #if defined(_MSC_VER)
892 #include "_MSC_VER/config.h"
902 #include "universalhdr.h"
905 #include "libelf/libelf.h"
906 #include "libelf/gelf.h"
907 #include "libdwarf.h"
908 #include "debugger/ELFManager.h"
909 #include "debugger/DBGManager.h"
912 // Private function prototypes
914 static int gzfilelength(gzFile gd
);
915 #if defined(_MSC_VER) || defined(__MINGW64__)|| defined(__MINGW32__) || defined(__CYGWIN__)
916 static bool CheckExtension(const uint8_t * filename
, const char * ext
);
918 static bool CheckExtension(const char * filename
, const char * ext
);
920 //static int ParseFileType(uint8_t header1, uint8_t header2, uint32_t size);
922 // Private variables/enums
926 // Generic ROM loading
928 uint32_t JaguarLoadROM(uint8_t * &rom
, char * path
)
930 // We really should have some kind of sanity checking for the ROM size here to prevent
931 // a buffer overflow... !!! FIX !!!
932 #if defined(_MSC_VER)
933 #pragma message("Warning: !!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!")
935 #warning "!!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!"
937 uint32_t romSize
= 0;
939 WriteLog("FILE: JaguarLoadROM attempting to load file '%s'...", path
);
940 char * ext
= strrchr(path
, '.');
942 // No filename extension == YUO FAIL IT (it is loading the file).
943 // This is naive, but it works. But should probably come up with something a little
944 // more robust, to prevent problems with dopes trying to exploit this.
947 WriteLog("FAILED!\n");
951 WriteLog("\nFILE: Succeeded in finding extension (%s)!\n", ext
);
952 WriteLog("FILE: Loading \"%s\"...", path
);
954 if (strcasecmp(ext
, ".zip") == 0)
956 // Handle ZIP file loading here...
957 WriteLog("(ZIPped)...");
959 // uint8_t * buffer = NULL;
960 // romSize = GetFileFromZIP(path, FT_SOFTWARE, buffer);
961 romSize
= GetFileFromZIP(path
, FT_SOFTWARE
, rom
);
965 WriteLog("Failed!\n");
969 // memcpy(rom, buffer, romSize);
974 // Handle gzipped files transparently [Adam Green]...
976 gzFile fp
= gzopen(path
, "rb");
980 WriteLog("Failed!\n");
984 romSize
= gzfilelength(fp
);
985 rom
= new uint8_t[romSize
];
986 gzseek(fp
, 0, SEEK_SET
);
987 gzread(fp
, rom
, romSize
);
991 WriteLog("OK (%i bytes)\n", romSize
);
998 // Jaguar file loading
999 // We do a more intelligent file analysis here instead of relying on (possible
1000 // false) file extensions which people don't seem to give two shits about
1003 bool JaguarLoadFile(char * path
)
1006 GElf_Ehdr ElfEhdr
, *PtrGElfEhdr
;
1008 Elf_Data
*PtrElfData
;
1009 GElf_Shdr GElfShdr
, *PtrGElfShdr
;
1011 uint8_t *buffer
= NULL
;
1013 size_t ElfSectionNameType
;
1014 int DBGType
= DBG_NO_TYPE
;
1018 jaguarROMSize
= JaguarLoadROM(buffer
, path
);
1020 if (jaguarROMSize
== 0)
1022 // It's up to the GUI to report errors, not us. :-)
1023 WriteLog("FILE: Could not load ROM from file \"%s\"...\nAborting load!\n", path
);
1027 jaguarMainROMCRC32
= crc32_calcCheckSum(buffer
, jaguarROMSize
);
1028 WriteLog("CRC: %08X\n", (unsigned int)jaguarMainROMCRC32
);
1029 // TODO: Check for EEPROM file in ZIP file. If there is no EEPROM in the user's EEPROM
1030 // directory, copy the one from the ZIP file, if it exists.
1032 jaguarRunAddress
= 0x802000; // For non-BIOS runs, this is true
1033 int fileType
= ParseFileType(buffer
, jaguarROMSize
);
1034 jaguarCartInserted
= false;
1037 if (fileType
== JST_ROM
)
1039 jaguarCartInserted
= true;
1040 memcpy(jagMemSpace
+ 0x800000, buffer
, jaguarROMSize
);
1041 // Checking something...
1042 jaguarRunAddress
= GET32(jagMemSpace
, 0x800404);
1043 WriteLog("FILE: Cartridge run address is reported as $%X...\n", jaguarRunAddress
);
1047 else if (fileType
== JST_ALPINE
)
1049 // File extension ".ROM": Alpine image that loads/runs at $802000
1050 WriteLog("FILE: Setting up Alpine ROM... Run address: 00802000, length: %08X\n", jaguarROMSize
);
1051 memset(jagMemSpace
+ 0x800000, 0xFF, 0x2000);
1052 memcpy(jagMemSpace
+ 0x802000, buffer
, jaguarROMSize
);
1055 // Maybe instead of this, we could try requiring the STUBULATOR ROM? Just a thought...
1056 // Try setting the vector to say, $1000 and putting an instruction there that loops forever:
1057 // This kludge works! Yeah!
1058 SET32(jaguarMainRAM
, 0x10, 0x00001000);
1059 SET16(jaguarMainRAM
, 0x1000, 0x60FE); // Here: bra Here
1062 else if (fileType
== JST_ELF32
)
1066 char *PtrELFExe
= (char *)ELFManager_ExeCopy(buffer
, jaguarROMSize
);
1068 if (PtrELFExe
!= NULL
)
1070 if ((elf_version(EV_CURRENT
) != EV_NONE
) && (ElfMem
= ELFManager_MemOpen(PtrELFExe
, jaguarROMSize
)))
1072 if (ELFManager_DwarfInit(ElfMem
))
1074 DBGType
|= DBG_ELFDWARF
;
1077 if (!elf_getshdrnum(ElfMem
, &NbrSect
))
1079 if (((PtrGElfEhdr
= gelf_getehdr(ElfMem
, &ElfEhdr
)) != NULL
) && ((PtrElfScn
= elf_getscn(ElfMem
, 0)) != NULL
))
1081 for (error
= false; (PtrElfScn
!= NULL
) && (error
== false); PtrElfScn
= elf_nextscn(ElfMem
, PtrElfScn
))
1085 if ((PtrGElfShdr
= gelf_getshdr(PtrElfScn
, &GElfShdr
)) == NULL
)
1091 NameSection
= elf_strptr(ElfMem
, PtrGElfEhdr
->e_shstrndx
, (size_t)PtrGElfShdr
->sh_name
);
1092 WriteLog("FILE: ELF Section name: %s\n", NameSection
);
1094 if ((ElfSectionNameType
= ELFManager_GetSectionType(NameSection
)) == ELF_NO_TYPE
)
1096 WriteLog("FILE: ELF Section not listed\n");
1101 switch (PtrGElfShdr
->sh_type
)
1107 if ((PtrGElfShdr
->sh_flags
& (SHF_ALLOC
| SHF_WRITE
| SHF_EXECINSTR
)))
1109 if (PtrGElfShdr
->sh_addr
>= 0x800000)
1111 memcpy(jagMemSpace
+ PtrGElfShdr
->sh_addr
, buffer
+ PtrGElfShdr
->sh_offset
, PtrGElfShdr
->sh_size
);
1116 memcpy(jaguarMainRAM
+ PtrGElfShdr
->sh_addr
, buffer
+ PtrGElfShdr
->sh_offset
, PtrGElfShdr
->sh_size
);
1121 switch (ElfSectionNameType
)
1123 case ELF_debug_aranges_TYPE
:
1124 case ELF_debug_info_TYPE
:
1125 case ELF_debug_abbrev_TYPE
:
1126 case ELF_debug_line_TYPE
:
1127 case ELF_debug_frame_TYPE
:
1128 case ELF_debug_ranges_TYPE
:
1129 case ELF_debug_str_TYPE
:
1130 case ELF_debug_loc_TYPE
:
1133 case ELF_comment_TYPE
:
1148 while ((error
== false) && ((PtrElfData
= elf_getdata(PtrElfScn
, PtrElfData
)) != NULL
))
1150 if (!ELFManager_AddTab(PtrElfData
, ElfSectionNameType
))
1165 jaguarRunAddress
= (uint32_t)PtrGElfEhdr
->e_entry
;
1166 WriteLog("FILE: Setting up ELF 32bits... Run address: %08X\n", jaguarRunAddress
);
1181 WriteLog("FILE: libelf version is not recognized or libelf memory cannot be opened\n");
1187 WriteLog("FILE: ELFManager cannot allocate memory\n");
1194 WriteLog("FILE: ELF parsing error\n");
1196 if (err
= elf_errno())
1198 WriteLog("FILE: ELF error: %s\n", elf_errmsg(err
));
1205 DBGManager_SetType(DBGType
);
1209 else if (fileType
== JST_ABS_TYPE1
)
1211 // For ABS type 1, run address == load address
1212 uint32_t loadAddress
= GET32(buffer
, 0x16),
1213 codeSize
= GET32(buffer
, 0x02) + GET32(buffer
, 0x06);
1214 WriteLog("FILE: Setting up homebrew (ABS-1)... Run address: %08X, length: %08X\n", loadAddress
, codeSize
);
1215 memcpy(jagMemSpace
+ loadAddress
, buffer
+ 0x24, codeSize
);
1217 jaguarRunAddress
= loadAddress
;
1220 else if (fileType
== JST_ABS_TYPE2
)
1222 uint32_t loadAddress
= GET32(buffer
, 0x28), runAddress
= GET32(buffer
, 0x24),
1223 codeSize
= GET32(buffer
, 0x18) + GET32(buffer
, 0x1C);
1224 WriteLog("FILE: Setting up homebrew (ABS-2)... Run address: %08X, length: %08X\n", runAddress
, codeSize
);
1225 memcpy(jagMemSpace
+ loadAddress
, buffer
+ 0xA8, codeSize
);
1227 jaguarRunAddress
= runAddress
;
1230 // NB: This is *wrong*
1232 Basically, if there is no "JAG" at position $1C, then the long there is the load/start
1233 address in LITTLE ENDIAN.
1234 If "JAG" is present, the the next character ("R" or "L") determines the size of the
1235 JagServer command (2 bytes vs. 4). Following that are the commands themselves;
1236 typically it will either be 2 (load) or 3 (load & run). Command headers go like so:
1252 Start address (long)
1255 10: (Poll for commands)
1257 12: (Load & run user program)
1258 filname, terminated with NULL
1263 else if (fileType
== JST_JAGSERVER
)
1265 // This kind of shiaut should be in the detection code below...
1266 // (and now it is! :-)
1267 // if (buffer[0x1C] == 'J' && buffer[0x1D] == 'A' && buffer[0x1E] == 'G')
1269 // Still need to do some checking here for type 2 vs. type 3. This assumes 3
1270 // Also, JAGR vs. JAGL (word command size vs. long command size)
1271 uint32_t loadAddress
= GET32(buffer
, 0x22), runAddress
= GET32(buffer
, 0x2A);
1272 WriteLog("FILE: Setting up homebrew (Jag Server)... Run address: $%X, length: $%X\n", runAddress
, jaguarROMSize
- 0x2E);
1273 memcpy(jagMemSpace
+ loadAddress
, buffer
+ 0x2E, jaguarROMSize
- 0x2E);
1275 jaguarRunAddress
= runAddress
;
1277 // Hmm. Is this kludge necessary?
1278 SET32(jaguarMainRAM
, 0x10, 0x00001000); // Set Exception #4 (Illegal Instruction)
1279 SET16(jaguarMainRAM
, 0x1000, 0x60FE); // Here: bra Here
1283 // else // Special WTFOMGBBQ type here...
1285 // uint32_t loadAddress = (buffer[0x1F] << 24) | (buffer[0x1E] << 16) | (buffer[0x1D] << 8) | buffer[0x1C];
1286 // WriteLog("FILE: Setting up homebrew (GEMDOS WTFOMGBBQ type)... Run address: $%X, length: $%X\n", loadAddress, jaguarROMSize - 0x20);
1287 // memcpy(jagMemSpace + loadAddress, buffer + 0x20, jaguarROMSize - 0x20);
1289 // jaguarRunAddress = loadAddress;
1293 else if (fileType
== JST_WTFOMGBBQ
)
1295 uint32_t loadAddress
= (buffer
[0x1F] << 24) | (buffer
[0x1E] << 16) | (buffer
[0x1D] << 8) | buffer
[0x1C];
1296 WriteLog("FILE: Setting up homebrew (GEMDOS WTFOMGBBQ type)... Run address: $%X, length: $%X\n", loadAddress
, jaguarROMSize
- 0x20);
1297 memcpy(jagMemSpace
+ loadAddress
, buffer
+ 0x20, jaguarROMSize
- 0x20);
1299 jaguarRunAddress
= loadAddress
;
1303 // We can assume we have JST_NONE at this point. :-P
1304 WriteLog("FILE: Failed to load headerless file.\n");
1310 // "Debugger" file loading
1311 // To keep the things separate between "Debugger" and "Alpine" loading until usage clarification has been done
1313 bool DebuggerLoadFile(char * path
)
1315 return (AlpineLoadFile(path
));
1320 // "Alpine" file loading
1321 // Since the developers were coming after us with torches and pitchforks, we
1322 // decided to allow this kind of thing. ;-) But ONLY FOR THE DEVS, DAMMIT! >:-U
1325 bool AlpineLoadFile(char * path
)
1327 uint8_t * buffer
= NULL
;
1328 jaguarROMSize
= JaguarLoadROM(buffer
, path
);
1330 if (jaguarROMSize
== 0)
1332 // It's up to the GUI to deal with failure, not us. ;-)
1333 WriteLog("FILE: Could not load Alpine from file \"%s\"...\nAborting load!\n", path
);
1337 jaguarMainROMCRC32
= crc32_calcCheckSum(buffer
, jaguarROMSize
);
1338 WriteLog("FILE: CRC is %08X\n", (unsigned int)jaguarMainROMCRC32
);
1341 jaguarRunAddress
= 0x802000;
1343 WriteLog("FILE: Setting up Alpine ROM with non-standard length... Run address: 00802000, length: %08X\n", jaguarROMSize
);
1345 memset(jagMemSpace
+ 0x800000, 0xFF, 0x2000);
1346 memcpy(jagMemSpace
+ 0x802000, buffer
, jaguarROMSize
);
1349 // Maybe instead of this, we could try requiring the STUBULATOR ROM? Just a thought...
1350 // Try setting the vector to say, $1000 and putting an instruction there
1351 // that loops forever:
1352 // This kludge works! Yeah!
1353 SET32(jaguarMainRAM
, 0x10, 0x00001000); // Set Exception #4 (Illegal Instruction)
1354 SET16(jaguarMainRAM
, 0x1000, 0x60FE); // Here: bra Here
1361 // Get the length of a (possibly) gzipped file
1363 static int gzfilelength(gzFile gd
)
1365 int size
= 0, length
= 0;
1366 unsigned char buffer
[0x10000];
1372 // Read in chunks until EOF
1373 size
= gzread(gd
, buffer
, 0x10000);
1388 // Compare extension to passed in filename. If equal, return true; otherwise false.
1390 #if defined(_MSC_VER) || defined(__MINGW64__)|| defined(__MINGW32__) || defined(__CYGWIN__)
1391 static bool CheckExtension(const uint8_t * filename
, const char * ext
)
1393 static bool CheckExtension(const char * filename
, const char * ext
)
1396 // Sanity checking...
1397 if ((filename
== NULL
) || (ext
== NULL
))
1400 const char * filenameExt
= strrchr((const char *)filename
, '.'); // Get the file's extension (if any)
1402 if (filenameExt
== NULL
)
1405 return (strcasecmp(filenameExt
, ext
) == 0 ? true : false);
1410 // Get file from .ZIP
1411 // Returns the size of the file inside the .ZIP file that we're looking at
1412 // NOTE: If the thing we're looking for is found, it allocates it in the passed in buffer.
1413 // Which means we have to deallocate it later.
1415 uint32_t GetFileFromZIP(const char * zipFile
, FileType type
, uint8_t * &buffer
)
1417 // NOTE: We could easily check for this by discarding anything that's larger than the RAM/ROM
1418 // size of the Jaguar console.
1419 #if defined(_MSC_VER)
1420 #pragma message("Warning: !!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!")
1422 #warning "!!! FIX !!! Should have sanity checking for ROM size to prevent buffer overflow!"
1424 const char ftStrings
[5][32] = { "Software", "EEPROM", "Label", "Box Art", "Controller Overlay" };
1425 // ZIP * zip = openzip(0, 0, zipFile);
1426 FILE * zip
= fopen(zipFile
, "rb");
1430 WriteLog("FILE: Could not open file '%s'!\n", zipFile
);
1438 // The order is here is important: If the file is found, we need to short-circuit the
1439 // readzip() call because otherwise, 'ze' will be pointing to the wrong file!
1440 // while (!found && readzip(zip))
1441 while (!found
&& GetZIPHeader(zip
, ze
))
1445 // Here we simply rely on the file extension to tell the truth, but we know
1446 // that extensions lie like sons-a-bitches. So this is naive, we need to do
1447 // something a little more robust to keep bad things from happening here.
1448 #if defined(_MSC_VER)
1449 #pragma message("Warning: !!! Checking for image by extension can be fooled !!!")
1451 #warning "!!! Checking for image by extension can be fooled !!!"
1453 if ((type
== FT_LABEL
) && (CheckExtension(ze
.filename
, ".png") || CheckExtension(ze
.filename
, ".jpg") || CheckExtension(ze
.filename
, ".gif")))
1456 WriteLog("FILE: Found image file '%s'.\n", ze
.filename
);
1459 if ((type
== FT_SOFTWARE
) && (CheckExtension(ze
.filename
, ".j64")
1460 || CheckExtension(ze
.filename
, ".rom") || CheckExtension(ze
.filename
, ".abs")
1461 || CheckExtension(ze
.filename
, ".cof") || CheckExtension(ze
.filename
, ".coff")
1462 || CheckExtension(ze
.filename
, ".jag") || CheckExtension(ze
.filename
, ".elf")))
1465 WriteLog("FILE: Found software file '%s'.\n", ze
.filename
);
1468 if ((type
== FT_EEPROM
) && (CheckExtension(ze
.filename
, ".eep") || CheckExtension(ze
.filename
, ".eeprom")))
1471 WriteLog("FILE: Found EEPROM file '%s'.\n", ze
.filename
);
1475 fseek(zip
, ze
.compressedSize
, SEEK_CUR
);
1478 uint32_t fileSize
= 0;
1482 WriteLog("FILE: Uncompressing...");
1483 // Insert file size sanity check here...
1484 buffer
= new uint8_t[ze
.uncompressedSize
];
1486 // if (readuncompresszip(zip, ze.compressedSize, buffer) == 0)
1487 // if (UncompressFileFromZIP(zip, ze.compressedSize, buffer) == 0)
1488 if (UncompressFileFromZIP(zip
, ze
, buffer
) == 0)
1490 fileSize
= ze
.uncompressedSize
;
1491 WriteLog("success! (%u bytes)\n", fileSize
);
1497 WriteLog("FAILED!\n");
1501 // Didn't find what we're looking for...
1502 WriteLog("FILE: Failed to find file of type %s...\n", ftStrings
[type
]);
1510 uint32_t GetFileDBIdentityFromZIP(const char * zipFile
)
1512 FILE * zip
= fopen(zipFile
, "rb");
1516 WriteLog("FILE: Could not open file '%s'!\n", zipFile
);
1522 // Loop through all files in the zip file under consideration
1523 while (GetZIPHeader(zip
, ze
))
1525 // & loop through all known CRC32s in our file DB to see if it's there!
1528 while (romList
[index
].crc32
!= 0xFFFFFF)
1530 if (romList
[index
].crc32
== ze
.crc32
)
1539 // We didn't find it, so skip the compressed data...
1540 fseek(zip
, ze
.compressedSize
, SEEK_CUR
);
1548 bool FindFileInZIPWithCRC32(const char * zipFile
, uint32_t crc
)
1550 FILE * zip
= fopen(zipFile
, "rb");
1554 WriteLog("FILE: Could not open file '%s'!\n", zipFile
);
1560 // Loop through all files in the zip file under consideration
1561 while (GetZIPHeader(zip
, ze
))
1563 if (ze
.crc32
== crc
)
1569 fseek(zip
, ze
.compressedSize
, SEEK_CUR
);
1578 // Parse the file type based upon file size and/or headers.
1580 uint32_t ParseFileType(uint8_t * buffer
, uint32_t size
)
1582 // Check headers first...
1585 if (buffer
[EI_CLASS
] == ELFCLASS32
)
1587 if (((BigToLittleEndian16(((Elf32_Ehdr
*)buffer
)->e_machine
) & 0xFF) == EM_68K
) && (BigToLittleEndian16(((Elf32_Ehdr
*)buffer
)->e_type
) == ET_EXEC
) && (buffer
[0] == ELFMAG0
) && (buffer
[1] == ELFMAG1
) && (buffer
[2] == ELFMAG2
) && (buffer
[3] == ELFMAG3
))
1592 if (buffer
[0] == 0x60 && buffer
[1] == 0x1B)
1593 return JST_ABS_TYPE1
;
1596 if (buffer
[0] == 0x01 && buffer
[1] == 0x50)
1597 return JST_ABS_TYPE2
;
1599 // Jag Server & other old shite
1600 if (buffer
[0] == 0x60 && buffer
[1] == 0x1A)
1602 if (buffer
[0x1C] == 'J' && buffer
[0x1D] == 'A' && buffer
[0x1E] == 'G')
1603 return JST_JAGSERVER
;
1605 return JST_WTFOMGBBQ
;
1608 // And if that fails, try file sizes...
1610 // If the file size is divisible by 1M, we probably have an regular ROM.
1611 // We can also check our CRC32 against the internal ROM database to be sure.
1612 // (We also check for the Memory Track cartridge size here as well...)
1613 if ((size
% 1048576) == 0 || size
== 131072)
1616 // If the file size + 8192 bytes is divisible by 1M, we probably have an
1617 // Alpine format ROM.
1618 if (((size
+ 8192) % 1048576) == 0)
1626 // Check for universal header
1628 bool HasUniversalHeader(uint8_t * rom
, uint32_t romSize
)
1634 for(int i
=0; i
<8192; i
++)
1635 if (rom
[i
] != universalCartHeader
[i
])
1645 Stubulator ROM vectors...
1646 handler 001 at $00E00008
1647 handler 002 at $00E008DE
1648 handler 003 at $00E008E2
1649 handler 004 at $00E008E6
1650 handler 005 at $00E008EA
1651 handler 006 at $00E008EE
1652 handler 007 at $00E008F2
1653 handler 008 at $00E0054A
1654 handler 009 at $00E008FA
1655 handler 010 at $00000000
1656 handler 011 at $00000000
1657 handler 012 at $00E008FE
1658 handler 013 at $00E00902
1659 handler 014 at $00E00906
1660 handler 015 at $00E0090A
1661 handler 016 at $00E0090E
1662 handler 017 at $00E00912
1663 handler 018 at $00E00916
1664 handler 019 at $00E0091A
1665 handler 020 at $00E0091E
1666 handler 021 at $00E00922
1667 handler 022 at $00E00926
1668 handler 023 at $00E0092A
1669 handler 024 at $00E0092E
1670 handler 025 at $00E0107A
1671 handler 026 at $00E0107A
1672 handler 027 at $00E0107A
1673 handler 028 at $00E008DA
1674 handler 029 at $00E0107A
1675 handler 030 at $00E0107A
1676 handler 031 at $00E0107A
1677 handler 032 at $00000000
1679 Let's try setting up the illegal instruction vector for a stubulated jaguar...
1681 SET32(jaguar_mainRam, 0x08, 0x00E008DE);
1682 SET32(jaguar_mainRam, 0x0C, 0x00E008E2);
1683 SET32(jaguar_mainRam, 0x10, 0x00E008E6); // <-- Should be here (it is)...
1684 SET32(jaguar_mainRam, 0x14, 0x00E008EA);//*/
1687 ABS Format sleuthing (LBUGDEMO.ABS):
1689 000000 60 1B 00 00 05 0C 00 04 62 C0 00 00 04 28 00 00
1690 000010 12 A6 00 00 00 00 00 80 20 00 FF FF 00 80 25 0C
1693 DRI-format file detected...
1694 Text segment size = 0x0000050c bytes
1695 Data segment size = 0x000462c0 bytes
1696 BSS Segment size = 0x00000428 bytes
1697 Symbol Table size = 0x000012a6 bytes
1698 Absolute Address for text segment = 0x00802000
1699 Absolute Address for data segment = 0x0080250c
1700 Absolute Address for BSS segment = 0x00004000
1703 000000 01 50 00 03 00 00 00 00 00 03 83 10 00 00 05 3b
1704 000010 00 1c 00 03 00 00 01 07 00 00 1d d0 00 03 64 98
1705 000020 00 06 8b 80 00 80 20 00 00 80 20 00 00 80 3d d0
1707 000030 2e 74 78 74 00 00 00 00 00 80 20 00 00 80 20 00 .txt (+36 bytes)
1708 000040 00 00 1d d0 00 00 00 a8 00 00 00 00 00 00 00 00
1709 000050 00 00 00 00 00 00 00 20
1710 000058 2e 64 74 61 00 00 00 00 00 80 3d d0 00 80 3d d0 .dta (+36 bytes)
1711 000068 00 03 64 98 00 00 1e 78 00 00 00 00 00 00 00 00
1712 000078 00 00 00 00 00 00 00 40
1713 000080 2e 62 73 73 00 00 00 00 00 00 50 00 00 00 50 00 .bss (+36 bytes)
1714 000090 00 06 8b 80 00 03 83 10 00 00 00 00 00 00 00 00
1715 0000a0 00 00 00 00 00 00 00 80
1717 Header size is $A8 bytes...
1719 BSD/COFF format file detected...
1720 3 sections specified
1721 Symbol Table offset = 230160 ($00038310)
1722 Symbol Table contains 1339 symbol entries ($0000053B)
1723 The additional header size is 28 bytes ($001C)
1724 Magic Number for RUN_HDR = 0x00000107
1725 Text Segment Size = 7632 ($00001DD0)
1726 Data Segment Size = 222360 ($00036498)
1727 BSS Segment Size = 428928 ($00068B80)
1728 Starting Address for executable = 0x00802000
1729 Start of Text Segment = 0x00802000
1730 Start of Data Segment = 0x00803dd0
1733 >>>>>>> parent of dfd8b1d
... Delete file
.cpp