Exemplo n.º 1
0
        // 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);
        }