Beispiel #1
0
        /// <summary>
        /// Analyzes uncategorized regions of the file to see if they fit common patterns.
        ///
        /// This is re-run after most changes to the project, so we don't want to do anything
        /// crazily expensive.
        /// </summary>
        /// <returns>True on success.</returns>
        public void AnalyzeUncategorized()
        {
            // TODO(someday): we can make this faster.  The data doesn't change, so we
            // only need to do a full scan once, when the file is first loaded.  We can
            // create a TypedRangeSet for runs of identical bytes, using the byte value
            // as the type.  A second TypedRangeSet would identify runs of ASCII chars,
            // with different types for high/low ASCII (and PETSCII?).  AnalyzeRange() would
            // then just need to find the intersection with the sets, which should be
            // significantly faster.  We would need to re-do the scan if the parameters
            // for things like min match length change.

            FormatDescriptor oneByteDefault = FormatDescriptor.Create(1,
                                                                      FormatDescriptor.Type.Default, FormatDescriptor.SubType.None);

            FormatDescriptor.DebugPrefabBump(-1);

            // If it hasn't been identified as code or data, set the "data" flag to
            // give it a positive identification as data.  (This should be the only
            // place outside of CodeAnalysis that sets this flag.)  This isn't strictly
            // necessary, but it helps us assert things when pieces start moving around.
            for (int offset = 0; offset < mAnattribs.Length; offset++)
            {
                Anattrib attr = mAnattribs[offset];
                if (attr.IsInlineData)
                {
                    // While we're here, add a default format descriptor for inline data
                    // that doesn't have one.  We don't try to analyze it otherwise.
                    if (attr.DataDescriptor == null)
                    {
                        mAnattribs[offset].DataDescriptor = oneByteDefault;
                        FormatDescriptor.DebugPrefabBump();
                    }
                }
                else if (!attr.IsInstruction)
                {
                    mAnattribs[offset].IsData = true;
                }
            }

            mDebugLog.LogI("Analyzing uncategorized data...");

            int startOffset = -1;

            for (int offset = 0; offset < mAnattribs.Length;)
            {
                // We want to find a contiguous series of offsets which are not known
                // to hold code or data.  We stop if we encounter a user-defined label
                // or format descriptor.
                Anattrib attr = mAnattribs[offset];

                if (attr.IsInstruction || attr.IsInlineData || attr.IsDataStart)
                {
                    // Instruction, inline data, or formatted data known to be here.  Analyze
                    // previous chunk, then advance past this.
                    if (startOffset >= 0)
                    {
                        AnalyzeRange(startOffset, offset - 1);
                        startOffset = -1;
                    }
                    if (attr.IsInstruction)
                    {
                        // Because of embedded instructions, we can't simply leap forward.
                        offset++;
                    }
                    else
                    {
                        Debug.Assert(attr.Length > 0);
                        offset += attr.Length;
                    }
                }
                else if (attr.Symbol != null || mProject.HasCommentOrNote(offset))
                {
                    // In an uncategorized area, but we want to break at this byte
                    // so the user or auto label doesn't get buried in the middle of
                    // a large chunk.
                    //
                    // This is similar to, but independent of, GroupedOffsetSetFromSelected()
                    // in ProjectView.  This is for auto-detection, the other is for user
                    // selection.  It's best if the two behave similarly though.
                    if (startOffset >= 0)
                    {
                        AnalyzeRange(startOffset, offset - 1);
                    }
                    startOffset = offset;
                    offset++;
                }
                else
                {
                    // This offset is uncategorized, keep gathering.
                    if (startOffset < 0)
                    {
                        startOffset = offset;
                    }
                    offset++;

                    // Check to see if the address has changed from the previous entry.
                    if (offset < mAnattribs.Length &&
                        mAnattribs[offset - 1].Address + 1 != mAnattribs[offset].Address)
                    {
                        // Must be an ORG here.  Scan previous region.
                        AnalyzeRange(startOffset, offset - 1);
                        startOffset = -1;
                    }
                }
            }
            if (startOffset >= 0)
            {
                AnalyzeRange(startOffset, mAnattribs.Length - 1);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Formats the address map for viewing.
        /// </summary>
        public static string GenerateString(DisasmProject project, Formatter formatter)
        {
            AddressMap addrMap  = project.AddrMap;
            bool       showBank = !project.CpuDef.HasAddr16;

            StringBuilder sb            = new StringBuilder();
            int           depth         = 0;
            int           prevOffset    = -1;
            int           prevAddr      = 0;
            int           lastEndOffset = -1;

            sb.AppendLine("Address region map for \"" + project.DataFileName + "\"");
            sb.Append(CRLF);

            IEnumerator <AddressChange> iter = addrMap.AddressChangeIterator;

            while (iter.MoveNext())
            {
                AddressChange change = iter.Current;
                if (change.IsStart)
                {
                    //if (change.Offset == lastEndOffset) {
                    //    // Extra vertical space for a START following an END at the same offset.
                    //    PrintDepthLines(sb, depth, true);
                    //    sb.Append(CRLF);
                    //    lastEndOffset = -1;
                    //}

                    if (prevOffset >= 0 && change.Offset != prevOffset)
                    {
                        // Start of region at new offset.  Output address info for space
                        // between previous start or end.
                        PrintAddressInfo(sb, formatter, depth, prevAddr,
                                         change.Offset - prevOffset, showBank);
                    }

                    // Start following end, or start following start after a gap.
                    sb.Append(formatter.FormatOffset24(change.Offset));
                    PrintDepthLines(sb, depth, false);
                    sb.Append("+- " + "start");

                    if (change.IsSynthetic)
                    {
                        sb.Append(" (auto-generated)");
                    }
                    else
                    {
                        // If there's a label here, show it.
                        Anattrib attr = project.GetAnattrib(change.Offset);
                        if (attr.Symbol != null && !string.IsNullOrEmpty(attr.Symbol.Label))
                        {
                            sb.Append(" '");
                            sb.Append(attr.Symbol.GenerateDisplayLabel(formatter));
                            sb.Append("'");
                        }
                    }
                    if (change.Region.HasValidPreLabel)
                    {
                        sb.Append("  pre='");
                        sb.Append(change.Region.PreLabel);
                        sb.Append("'");
                    }

                    sb.Append(CRLF);

                    prevOffset = change.Offset;
                    prevAddr   = change.Address;
                    depth++;
                }
                else
                {
                    Debug.Assert(prevOffset >= 0);
                    depth--;

                    if (change.Offset + 1 != prevOffset)
                    {
                        // End of region at new offset.  Output address info for space
                        // between previous start or end.
                        PrintAddressInfo(sb, formatter, depth + 1, prevAddr,
                                         change.Offset + 1 - prevOffset, showBank);
                    }

                    sb.Append(formatter.FormatOffset24(change.Offset));
                    PrintDepthLines(sb, depth, false);
                    sb.Append("+- " + "end");
                    if (change.Region.IsFloating)
                    {
                        sb.Append(" (floating)");
                    }
                    //PrintAddress(sb, formatter, change.Address, showBank);
                    //sb.Append(")");
                    sb.Append(CRLF);

                    // Add a blank line, but with the depth lines.
                    if (depth > 0)
                    {
                        PrintDepthLines(sb, depth, true);
                    }
                    sb.Append(CRLF);

                    // Use offset+1 here so it lines up with start records.
                    prevOffset = lastEndOffset = change.Offset + 1;
                    prevAddr   = change.Address;
                }
            }
            Debug.Assert(depth == 0);

            return(sb.ToString());
        }
Beispiel #3
0
        /// <summary>
        /// Analyzes instruction operands and Address data descriptors to identify references
        /// to offsets within the file.
        ///
        /// Instructions with format descriptors are left alone.  Instructions with
        /// operand offsets but no descriptor will have a descriptor generated
        /// using the label at the target offset; if the target offset is unlabeled,
        /// a unique label will be generated.  Data descriptors with type=Address are
        /// handled the same way.
        ///
        /// In some cases, such as a reference to the middle of an instruction, we will
        /// label a nearby location instead.
        ///
        /// This should be called after code analysis has run, user labels and format
        /// descriptors have been applied, and platform/project symbols have been merged
        /// into the symbol table.
        /// </summary>
        /// <returns>True on success.</returns>
        public void AnalyzeDataTargets()
        {
            mDebugLog.LogI("Analyzing data targets...");

            for (int offset = 0; offset < mAnattribs.Length; offset++)
            {
                Anattrib attr = mAnattribs[offset];
                if (attr.IsInstructionStart)
                {
                    if (attr.DataDescriptor != null)
                    {
                        // It's being shown as numeric, or as a reference to some other symbol.
                        // Either way there's nothing further for us to do.  (Technically we
                        // would want to treat it like the no-descriptor case if the type was
                        // numeric/Address, but we don't allow that for instructions.)
                        Debug.Assert(attr.DataDescriptor.FormatSubType !=
                                     FormatDescriptor.SubType.Address);
                        continue;
                    }
                    int operandOffset = attr.OperandOffset;
                    if (operandOffset >= 0)
                    {
                        // This is an offset reference: a branch or data access instruction whose
                        // target is inside the file.  Create a FormatDescriptor for it, and
                        // generate a label at the target if one is not already present.
                        SetDataTarget(offset, attr.Length, operandOffset);
                    }

                    // We advance by a single byte, rather than .Length, in case there's
                    // an instruction embedded inside another one.
                }
                else if (attr.DataDescriptor != null)
                {
                    // We can't check IsDataStart / IsInlineDataStart because the bytes might
                    // still be uncategorized.  If there's a user-specified format, check it
                    // to see if it's an address.
                    FormatDescriptor dfd = attr.DataDescriptor;

                    // Is this numeric/Address?
                    if ((dfd.FormatType == FormatDescriptor.Type.NumericLE ||
                         dfd.FormatType == FormatDescriptor.Type.NumericBE) &&
                        dfd.FormatSubType == FormatDescriptor.SubType.Address)
                    {
                        // Treat like an absolute address.  Convert the operand
                        // to an address, then resolve the file offset.
                        int address = RawData.GetWord(mFileData, offset, dfd.Length,
                                                      (dfd.FormatType == FormatDescriptor.Type.NumericBE));
                        if (dfd.Length < 3)
                        {
                            // Bank not specified by data, add current program bank.  Not always
                            // correct, but should be often enough.  In most cases we'd just
                            // assume a correct data bank register, but here we need to find
                            // a file offset, so we have to assume data bank == program bank
                            // (unless we find a good way to track the data bank register).
                            address |= attr.Address & 0x7fff0000;
                        }
                        int operandOffset = mProject.AddrMap.AddressToOffset(offset, address);
                        if (operandOffset >= 0)
                        {
                            SetDataTarget(offset, dfd.Length, operandOffset);
                        }
                    }

                    // For other formats, we don't need to do anything.  Numeric/Address is
                    // the only one that represents an offset reference.  Numeric/Symbol
                    // is a name reference.  The others are just data.

                    // There shouldn't be any data items inside other data items, so we
                    // can just skip forward.
                    offset += mAnattribs[offset].DataDescriptor.Length - 1;
                }
            }
        }