// Resolve hunks referenced in the index"; // From the hunk list build a set of segments that form the actual binary. // Return a summary of the created segment structure. public virtual HunkFile Parse() { this.hunks = new List <Hunk>(); bool isFirstHunk = true; bool sawEndHunk = false; bool was_potential_v37_hunk = false; bool sawOverlay = false; var lib_size = 0; uint last_file_offset = 0; while (true) { var hunkFileOffset = f.Offset; // read hunk type var rawHunkType = this.read_long(); if (rawHunkType == -1 || rawHunkType == -2) { // tolerate extra byte at end if (isFirstHunk) { throw new BadImageFormatException("Invalid hunk file. The file is empty."); } break; } var hunkType = (HunkType)(rawHunkType & Hunk.HUNK_TYPE_MASK); var hunkFlags = rawHunkType & Hunk.HUNK_FLAGS_MASK; // Validate that hunk type is known. if (!knownHunkTypes.ContainsKey(hunkType)) { // no hunk file? if (isFirstHunk) { throw new BadImageFormatException(String.Format("Unknown hunk type: {0}.", hunkType)); } if (sawEndHunk) { // garbage after an end tag is ignored return(this.hunk_file); } if (was_potential_v37_hunk) { // auto fix v37 -> reread whole file f.Offset = 0; v37_compat = true; return(this.Parse()); } if (sawOverlay) { // seems to be a custom overlay -> read to end of file var ov_custom_data = f.ReadToEnd(); ((OverlayHunk)this.hunk_file.hunks[hunks.Count - 1]).custom_data = ov_custom_data; return(this.hunk_file); } else { throw new BadImageFormatException( string.Format("Invalid hunk type {0}/{0:X} found at @{1:X8}.", hunkType, (int)hunkType, f.Offset)); } } // check for valid first hunk type if (isFirstHunk && !this.IsValidFirstHunkType(hunkType)) { throw new BadImageFormatException(String.Format("No hunk file. The first hunk type was {1}.", hunkType)); } isFirstHunk = false; sawEndHunk = false; was_potential_v37_hunk = false; sawOverlay = false; Action <Hunk> hunk = h => { h.HunkType = hunkType; h.FileOffset = (uint)hunkFileOffset; hunk_file.hunks.Add(h); h.memf = this.SetMemoryFlags(hunkFlags, 30); // Account for lib var last_hunk_size = (int)(hunkFileOffset - last_file_offset); if (lib_size > 0) { lib_size -= last_hunk_size; } if (lib_size > 0) { h.in_lib = true; } // V37 fix? if (hunkType == HunkType.HUNK_DREL32) { // try to fix automatically... if (v37_compat == null) { was_potential_v37_hunk = true; // fix was forced } else if (v37_compat.HasValue && v37_compat.Value) { hunkType = HunkType.HUNK_RELOC32SHORT; h.fixes = "v37"; } } }; Debug.WriteLineIf(trace.TraceVerbose, string.Format("Loading hunk type: {0}", hunkType)); switch (hunkType) { case HunkType.HUNK_HEADER: this.ParseHeader(hunk); break; case HunkType.HUNK_CODE: case HunkType.HUNK_DATA: case HunkType.HUNK_PPC_CODE: this.ParseText(hunk); break; case HunkType.HUNK_BSS: this.ParseBss(hunk); break; case HunkType.HUNK_RELRELOC32: case HunkType.HUNK_ABSRELOC16: case HunkType.HUNK_RELRELOC8: case HunkType.HUNK_RELRELOC16: case HunkType.HUNK_ABSRELOC32: case HunkType.HUNK_DREL32: case HunkType.HUNK_DREL16: case HunkType.HUNK_DREL8: case HunkType.HUNK_RELRELOC26: try { this.ParseReloc(hunk); } catch (BadImageFormatException) { // auto fix v37 bug? if (hunkType != HunkType.HUNK_DREL32 || v37_compat != null) { throw; } f.Offset = 0; v37_compat = true; return(Parse()); } break; case HunkType.HUNK_RELOC32SHORT: this.ParseRelocShort(hunk); break; case HunkType.HUNK_SYMBOL: this.ParseSymbol(hunk); break; case HunkType.HUNK_DEBUG: this.ParseDebug(hunk); break; case HunkType.HUNK_END: hunk(new Hunk()); sawEndHunk = true; break; case HunkType.HUNK_OVERLAY: this.ParseOverlay(hunk); sawOverlay = true; break; case HunkType.HUNK_BREAK: break; case HunkType.HUNK_LIB: lib_size = this.ParseLib(hunk); lib_size += 8; break; case HunkType.HUNK_INDEX: this.ParseIndex(hunk); break; case HunkType.HUNK_EXT: this.ParseExt(hunk); break; case HunkType.HUNK_UNIT: case HunkType.HUNK_NAME: this.parse_unit_or_name(hunk); break; default: throw new BadImageFormatException(string.Format("Unsupported hunk {0}.", (int)hunkType)); } last_file_offset = (uint)hunkFileOffset; } return(hunk_file); }