Exemplo n.º 1
0
        private void VerifyAndFixProgramHeadersAndSections()
        {
            if (!_isFirstSectionValidNull && ObjectFile.Sections.Count > 0)
            {
                Diagnostics.Error(DiagnosticId.ELF_ERR_InvalidFirstSectionExpectingUndefined, $"Invalid Section [0] {ObjectFile.Sections[0].Type}. Expecting {ElfNative.SHN_UNDEF}");
            }

            if (_hasValidSectionStringTable)
            {
                Stream.Position = (long)ObjectFile.SectionHeaderStringTable.Offset;
                ObjectFile.SectionHeaderStringTable.ReadInternal(this);
            }

            for (var i = 0; i < ObjectFile.Sections.Count; i++)
            {
                var section = ObjectFile.Sections[i];
                if (section is ElfNullSection || section is ElfProgramHeaderTable)
                {
                    continue;
                }

                // Resolve the name of the section
                if (ObjectFile.SectionHeaderStringTable != null && ObjectFile.SectionHeaderStringTable.TryFind(section.Name.Index, out var sectionName))
                {
                    section.Name = section.Name.WithName(sectionName);
                }
                else
                {
                    if (ObjectFile.SectionHeaderStringTable == null)
                    {
                        Diagnostics.Warning(DiagnosticId.ELF_ERR_InvalidStringIndexMissingStringHeaderTable, $"Unable to resolve string index [{section.Name.Index}] for section [{section.Index}] as section header string table does not exist");
                    }
                    else
                    {
                        Diagnostics.Warning(DiagnosticId.ELF_ERR_InvalidStringIndex, $"Unable to resolve string index [{section.Name.Index}] for section [{section.Index}] from section header string table");
                    }
                }

                // Connect section Link instance
                section.Link = ResolveLink(section.Link, $"Invalid section Link [{{0}}] for section [{i}]");

                // Connect section Info instance
                if (section.Type != ElfSectionType.DynamicLinkerSymbolTable && section.Type != ElfSectionType.SymbolTable)
                {
                    section.Info = ResolveLink(section.Info, $"Invalid section Info [{{0}}] for section [{i}]");
                }

                if (i == 0 && _isFirstSectionValidNull)
                {
                    continue;
                }

                if (i == _sectionStringTableIndex && _hasValidSectionStringTable)
                {
                    continue;
                }

                if (section.HasContent)
                {
                    Stream.Position = (long)section.Offset;
                    section.ReadInternal(this);
                }
            }

            foreach (var section in ObjectFile.Sections)
            {
                section.AfterReadInternal(this);
            }

            var fileParts = new ElfFilePartList(ObjectFile.Sections.Count + ObjectFile.Segments.Count);

            if (_isFirstSectionValidNull)
            {
                var programHeaderTable = new ElfProgramHeaderTable()
                {
                    Offset = Layout.OffsetOfProgramHeaderTable,
                };

                // Add the shadow section ElfProgramHeaderTable
                ObjectFile.InsertSectionAt(1, programHeaderTable);
                programHeaderTable.UpdateLayout(Diagnostics);

                if (programHeaderTable.Size > 0)
                {
                    fileParts.Insert(new ElfFilePart(programHeaderTable));
                }
            }

            // Make sure to pre-sort all sections by offset
            var orderedSections = new List <ElfSection>(ObjectFile.Sections.Count);

            orderedSections.AddRange(ObjectFile.Sections);
            orderedSections.Sort(CompareSectionOffsetsDelegate);
            // Store the stream index to recover the same order when saving back.
            for (int i = 0; i < orderedSections.Count; i++)
            {
                orderedSections[i].StreamIndex = (uint)i;
            }

            // Lastly verify integrity of all sections
            bool hasShadowSections = false;

            var lastOffset = fileParts.Count > 0 ? fileParts[fileParts.Count - 1].EndOffset : 0;

            for (var i = 0; i < orderedSections.Count; i++)
            {
                var section = orderedSections[i];
                section.Verify(this.Diagnostics);

                if (lastOffset > 0 && section.Offset > lastOffset)
                {
                    if (section.Offset > lastOffset)
                    {
                        // Create parts for the segment
                        fileParts.CreateParts(lastOffset + 1, section.Offset - 1);
                        hasShadowSections = true;
                    }
                }

                if (section.Size == 0 || !section.HasContent)
                {
                    continue;
                }

                // Collect sections parts
                fileParts.Insert(new ElfFilePart(section));
                lastOffset = section.Offset + section.Size - 1;

                // Verify overlapping sections and generate and error
                for (int j = i + 1; j < orderedSections.Count; j++)
                {
                    var otherSection = orderedSections[j];
                    if (section.Contains(otherSection) || otherSection.Contains(section))
                    {
                        Diagnostics.Warning(DiagnosticId.ELF_ERR_InvalidOverlappingSections, $"The section {section} [{section.Offset} : {section.Offset + section.Size - 1}] is overlapping with the section {otherSection} [{otherSection.Offset} : {otherSection.Offset + otherSection.Size - 1}]");
                    }
                }
            }

            // Link segments to sections if we have an exact match.
            // otherwise record any segments that are not bound to a section.

            foreach (var segment in ObjectFile.Segments)
            {
                if (segment.Size == 0)
                {
                    continue;
                }

                var segmentEndOffset = segment.Offset + segment.Size - 1;
                foreach (var section in orderedSections)
                {
                    if (section.Size == 0 || !section.HasContent)
                    {
                        continue;
                    }

                    var sectionEndOffset = section.Offset + section.Size - 1;
                    if (segment.Offset == section.Offset && segmentEndOffset == sectionEndOffset)
                    {
                        // Single case: segment == section
                        // If we found a section, we will bind the program header to this section
                        // and switch the offset calculation to auto
                        segment.Range      = section;
                        segment.OffsetKind = ValueKind.Auto;
                        break;
                    }
                }

                if (segment.Range.IsEmpty)
                {
                    var offset = segment.Offset;

                    // If a segment offset is set to 0, we need to take into
                    // account the fact that the Elf header is already being handled
                    // so we should not try to create a shadow section for it
                    if (offset < Layout.SizeOfElfHeader)
                    {
                        offset = Layout.SizeOfElfHeader;
                    }

                    // Create parts for the segment
                    fileParts.CreateParts(offset, segmentEndOffset);
                    hasShadowSections = true;
                }
            }

            // If the previous loop has created ElfFilePart, we have to
            // create ElfCustomShadowSection and update the ElfSegment.Range
            if (hasShadowSections)
            {
                int shadowCount = 0;
                // If we have sections and the first section is NULL valid, we can start inserting
                // shadow sections at index 1 (after null section), otherwise we can insert shadow
                // sections before.
                uint previousSectionIndex = _isFirstSectionValidNull ? 1U : 0U;

                // Create ElfCustomShadowSection for any parts in the file
                // that are referenced by a segment but doesn't have a section
                for (var i = 0; i < fileParts.Count; i++)
                {
                    var part = fileParts[i];
                    if (part.Section == null)
                    {
                        var shadowSection = new ElfBinaryShadowSection()
                        {
                            Name   = ".shadow." + shadowCount,
                            Offset = part.StartOffset,
                            Size   = part.EndOffset - part.StartOffset + 1
                        };
                        shadowCount++;

                        Stream.Position = (long)shadowSection.Offset;
                        shadowSection.ReadInternal(this);

                        // Insert the shadow section with this order
                        shadowSection.StreamIndex = previousSectionIndex;
                        for (int j = (int)previousSectionIndex; j < orderedSections.Count; j++)
                        {
                            var otherSection = orderedSections[j];
                            otherSection.StreamIndex++;
                        }
                        // Update ordered sections
                        orderedSections.Insert((int)previousSectionIndex, shadowSection);
                        ObjectFile.AddSection(shadowSection);

                        fileParts[i] = new ElfFilePart(shadowSection);
                    }
                    else
                    {
                        previousSectionIndex = part.Section.StreamIndex + 1;
                    }
                }

                // Update all segment Ranges
                foreach (var segment in ObjectFile.Segments)
                {
                    if (segment.Size == 0)
                    {
                        continue;
                    }
                    if (!segment.Range.IsEmpty)
                    {
                        continue;
                    }

                    var segmentEndOffset = segment.Offset + segment.Size - 1;
                    for (var i = 0; i < orderedSections.Count; i++)
                    {
                        var section = orderedSections[i];
                        if (section.Size == 0 || !section.HasContent)
                        {
                            continue;
                        }

                        var sectionEndOffset = section.Offset + section.Size - 1;
                        if (segment.Offset >= section.Offset && segment.Offset <= sectionEndOffset)
                        {
                            ElfSection beginSection = section;
                            ElfSection endSection   = null;
                            for (int j = i; j < orderedSections.Count; j++)
                            {
                                var nextSection = orderedSections[j];
                                if (nextSection.Size == 0 || !nextSection.HasContent)
                                {
                                    continue;
                                }

                                sectionEndOffset = nextSection.Offset + nextSection.Size - 1;

                                if (segmentEndOffset >= nextSection.Offset && segmentEndOffset <= sectionEndOffset)
                                {
                                    endSection = nextSection;
                                    break;
                                }
                            }

                            if (endSection == null)
                            {
                                // TODO: is it a throw/assert or a log?
                                Diagnostics.Error(DiagnosticId.ELF_ERR_InvalidSegmentRange, $"Invalid range for {segment}. The range is set to empty");
                            }
                            else
                            {
                                segment.Range = new ElfSegmentRange(beginSection, segment.Offset - beginSection.Offset, endSection, (long)(segmentEndOffset - endSection.Offset));
                            }

                            segment.OffsetKind = ValueKind.Auto;
                            break;
                        }
                    }
                }
            }
        }