public void AddResourcesToImageMap( Address addrLoad, MemoryArea mem, SegmentMap segmentMap, List <ImageSymbol> entryPoints, SortedList <Address, ImageSymbol> symbols) { JumpTable jt = null; var codeSegs = new Dictionary <int, ImageSegment>(); foreach (ResourceType type in ResourceTypes) { foreach (ResourceReference rsrc in type.References) { uint uSegOffset = rsrc.DataOffset + rsrcDataOff; int segmentSize = mem.ReadBeInt32(uSegOffset); // Skip the size longword at the beginning of the segment, and an extra 4 // if it is a code segement other than CODE#0. int bytesToSkip = 4; if (type.Name == "CODE" && rsrc.ResourceID != 0) { bytesToSkip += 4; } var abSegment = new byte[segmentSize]; Array.Copy(mem.Bytes, uSegOffset + bytesToSkip, abSegment, 0, segmentSize); Address addrSegment = addrLoad + uSegOffset + bytesToSkip; //$TODO pad to 16-byte boundary? var memSeg = new MemoryArea(addrSegment, abSegment); var segment = segmentMap.AddSegment(new ImageSegment( ResourceDescriptiveName(type, rsrc), memSeg, AccessMode.Read)); if (type.Name == "CODE") { if (rsrc.ResourceID == 0) { jt = ProcessJumpTable(memSeg, symbols); } else { codeSegs.Add(rsrc.ResourceID, segment); var macsBug = new MacsBugSymbolScanner(arch, segment.MemoryArea); var mbSymbols = macsBug.ScanForSymbols(); foreach (var symbol in mbSymbols) { symbols[symbol.Address] = symbol; } } } } } // We have found a jump table, so we allocate an A5World. if (jt != null) { // Find an address beyond all known segments. var addr = segmentMap.Segments.Values.Max(s => s.Address + s.Size).Align(0x10); var a5world = LoadA5World(jt, addr, codeSegs, symbols); platform.A5World = a5world; platform.A5Offset = jt.BelowA5Size; segmentMap.AddSegment(a5world); // Find first (and only!) segment containing the name %A5Init. var a5dataSegment = segmentMap.Segments.Values.SingleOrDefault(SegmentNamedA5Init); if (a5dataSegment == null) { return; } // Get an image reader to the start of the data. var a5dr = GetA5InitImageReader(a5dataSegment); if (a5dr == null) { return; } var a5hdroffset = a5dr.Offset; var a5dbelow = a5dr.ReadBeUInt32(); var a5dbankSize = a5dr.ReadBeUInt32(); var a5doffset = a5dr.ReadBeUInt32(); var a5dreloc = a5dr.ReadBeUInt32(); var a5dhdrend = a5dr.ReadBeUInt32(); if (a5dbankSize != 0x00010000) { // bank size not supported for compressed global data return; } A5Expand(a5dr, a5dbelow); a5dr.Seek(a5hdroffset + a5dreloc, System.IO.SeekOrigin.Begin); var relocator = new A5Relocator(platform, a5dr, a5dbelow); relocator.Relocate(); } }
// References: Inside Macintosh: Processes (Segment Manager) public void AddResourcesToImageMap( Address addrLoad, ByteMemoryArea mem, Program program) { JumpTable?jt = null; var codeSegs = new Dictionary <int, ImageSegment>(); foreach (ResourceType type in ResourceTypes) { foreach (ResourceReference rsrc in type.References) { uint uSegOffset = rsrc.DataOffset + rsrcDataOff; int segmentSize = mem.ReadBeInt32(uSegOffset); // Skip the size longword at the beginning of the segment, and an extra 4 // if it is a code segement other than CODE#0. int bytesToSkip = 4; if (type.Name == "CODE" && rsrc.ResourceID != 0) { bytesToSkip += 4; } var abSegment = new byte[segmentSize]; Array.Copy(mem.Bytes, uSegOffset + bytesToSkip, abSegment, 0, segmentSize); var uAddr = (uSegOffset + bytesToSkip) & ~1u; Address addrSegment = addrLoad + uAddr; //$TODO pad to 16-byte boundary? var memSeg = new ByteMemoryArea(addrSegment, abSegment); var segment = program.SegmentMap.AddSegment(new ImageSegment( ResourceDescriptiveName(type, rsrc), memSeg, AccessMode.Read)); if (type.Name == "CODE") { if (rsrc.ResourceID == 0) { jt = ProcessJumpTable(memSeg, program.ImageSymbols); } else { AddCodeSegment(program.ImageSymbols, codeSegs, rsrc, memSeg, segment); } } if (type.Name == "INIT") { AddCodeSegment(program.ImageSymbols, codeSegs, rsrc, memSeg, segment); var symInit = ImageSymbol.Procedure(arch, segment.Address, $"Init_{segment.Address}"); program.EntryPoints.Add(symInit.Address, symInit); } else if (type.Name == "cdev") { AddCodeSegment(program.ImageSymbols, codeSegs, rsrc, memSeg, segment); var symInit = ImageSymbol.Procedure(arch, segment.Address, $"CDev_{segment.Address}"); program.EntryPoints.Add(symInit.Address, symInit); } else if (type.Name == "DRVR") { AddCodeSegment(program.ImageSymbols, codeSegs, rsrc, memSeg, segment); var symInit = ImageSymbol.Procedure(arch, segment.Address, $"Drvr_{segment.Address}"); program.EntryPoints.Add(symInit.Address, symInit); AddDriverMethods(program.ImageSymbols, memSeg); } } } // We have found a jump table, so we allocate an A5World. if (jt != null) { // Find an address beyond all known segments. var addr = program.SegmentMap.Segments.Values.Max(s => s.Address + s.Size).Align(0x10); var a5world = LoadA5World(jt, addr, codeSegs, program.ImageSymbols); platform.A5World = a5world; platform.A5Offset = jt.BelowA5Size; program.SegmentMap.AddSegment(a5world); // Find first (and only!) segment containing the name %A5Init. var a5dataSegment = program.SegmentMap.Segments.Values.SingleOrDefault(SegmentNamedA5Init); if (a5dataSegment == null) { return; } // Get an image reader to the start of the data. var a5dr = GetA5InitImageReader(a5dataSegment); if (a5dr == null) { return; } var a5hdroffset = a5dr.Offset; var a5dbelow = a5dr.ReadBeUInt32(); var a5dbankSize = a5dr.ReadBeUInt32(); var a5doffset = a5dr.ReadBeUInt32(); var a5dreloc = a5dr.ReadBeUInt32(); var a5dhdrend = a5dr.ReadBeUInt32(); if (a5dbankSize != 0x00010000) { // bank size not supported for compressed global data return; } A5Expand(a5dr, a5dbelow); a5dr.Seek(a5hdroffset + a5dreloc, System.IO.SeekOrigin.Begin); var relocator = new A5Relocator(platform, a5dr, a5dbelow); relocator.Relocate(); } }