Exemple #1
0
        /// <summary>
        /// Creates one or more FormatDescriptor entries for the specified range, adding them
        /// to the Results list.
        ///
        /// This will either create one entry that spans the entire range (for e.g. strings
        /// and bulk data), or create equal-sized chunks.
        /// </summary>
        /// <param name="type">Region data type.</param>
        /// <param name="subType">Region data sub-type.</param>
        /// <param name="chunkLength">Length of a chunk, or -1 for full buffer.</param>
        /// <param name="symbolRef">Symbol reference, or null if not applicable.</param>
        /// <param name="low">Offset of first byte in range.</param>
        /// <param name="high">Offset of last byte in range.</param>
        private void CreateSimpleEntries(FormatDescriptor.Type type,
                                         FormatDescriptor.SubType subType, int chunkLength,
                                         WeakSymbolRef symbolRef, int low, int high)
        {
            if (chunkLength == -1)
            {
                chunkLength = (high - low) + 1;
            }
            Debug.Assert(((high - low + 1) / chunkLength) * chunkLength == high - low + 1);

            // Either we have one chunk, or we have multiple chunks with the same type and
            // length.  Either way, we only need to create the descriptor once.  (This is
            // safe because FormatDescriptor instances are immutable.)
            //
            // Because certain details, like the fill byte and high-vs-low ASCII, are pulled
            // out of the data stream at format time, we don't have to dig for them now.
            FormatDescriptor dfd;

            if (subType == FormatDescriptor.SubType.Symbol)
            {
                dfd = FormatDescriptor.Create(chunkLength, symbolRef,
                                              type == FormatDescriptor.Type.NumericBE);
            }
            else
            {
                dfd = FormatDescriptor.Create(chunkLength, type, subType);
            }

            while (low <= high)
            {
                Results.Add(low, dfd);
                low += chunkLength;
            }
        }
Exemple #2
0
        /// <summary>
        /// Creates one or more FormatDescriptor entries for the specified range, adding them
        /// to the Results list.
        /// </summary>
        /// <param name="low">Offset of first byte in range.</param>
        /// <param name="high">Offset of last byte in range.</param>
        /// <param name="subType">String sub-type.</param>
        private void CreateLengthStringEntries(int low, int high,
                                               FormatDescriptor.SubType subType)
        {
            int i;

            for (i = low; i <= high;)
            {
                int length = mFileData[i];
                if (subType == FormatDescriptor.SubType.L16String)
                {
                    length |= mFileData[i + 1] << 8;
                    length += 2;
                }
                else
                {
                    length++;
                }
                // Zero-length strings are allowed.
                FormatDescriptor dfd = FormatDescriptor.Create(length,
                                                               FormatDescriptor.Type.String, subType);
                Results.Add(i, dfd);
                i += length;
            }

            Debug.Assert(i == high + 1);
        }
Exemple #3
0
        /// <summary>
        /// Creates a format descriptor for a single-byte numeric value.
        /// </summary>
        /// <param name="offset">File offset.</param>
        /// <param name="subType">How to format the item.</param>
        private void CreateByteFD(int offset, FormatDescriptor.SubType subType)
        {
            FormatDescriptor dfd = FormatDescriptor.Create(1,
                                                           FormatDescriptor.Type.NumericLE, subType);

            Results.Add(offset, dfd);
        }
        // IGenerator
        public FormatDescriptor ModifyInstructionOperandFormat(int offset, FormatDescriptor dfd,
                                                               int operand)
        {
            if (dfd.FormatType == FormatDescriptor.Type.NumericLE && dfd.IsStringOrCharacter &&
                (operand & 0x7f) == (byte)',')
            {
                // Merlin throws an error on comma operands, e.g. LDA #','
                dfd = FormatDescriptor.Create(dfd.Length,
                                              FormatDescriptor.Type.NumericLE, FormatDescriptor.SubType.None);
            }

            return(dfd);
        }
Exemple #5
0
        // IGenerator
        public FormatDescriptor ModifyInstructionOperandFormat(int offset, FormatDescriptor dfd,
                                                               int operand)
        {
            string badChars = ",{}";

            if (dfd.FormatType == FormatDescriptor.Type.NumericLE && dfd.IsStringOrCharacter &&
                badChars.IndexOf((char)(operand & 0x7f)) >= 0)
            {
                // Merlin throws an error on certain ASCII operands, e.g. LDA #','
                dfd = FormatDescriptor.Create(dfd.Length,
                                              FormatDescriptor.Type.NumericLE, FormatDescriptor.SubType.None);
            }

            return(dfd);
        }
Exemple #6
0
 /// <summary>
 /// Creates a format descriptor for ASCII data.  If the data is only one byte long,
 /// a single-byte ASCII char item is emitted instead.
 /// </summary>
 /// <param name="offset">Offset of first byte.</param>
 /// <param name="length">Length of string.</param>
 /// <param name="subType">String sub-type.</param>
 private void CreateStringOrByte(int offset, int length,
                                 FormatDescriptor.SubType subType)
 {
     Debug.Assert(length > 0);
     if (length == 1)
     {
         // single byte, output as single ASCII char rather than 1-byte string
         CreateByteFD(offset, FormatDescriptor.SubType.Ascii);
     }
     else
     {
         FormatDescriptor dfd;
         dfd = FormatDescriptor.Create(length,
                                       FormatDescriptor.Type.String, subType);
         Results.Add(offset, dfd);
     }
 }
Exemple #7
0
        /// <summary>
        /// Creates one or more FormatDescriptor entries for the specified range, adding them
        /// to the Results list.
        /// </summary>
        /// <param name="low">Offset of first byte in range.</param>
        /// <param name="high">Offset of last byte in range.</param>
        /// <param name="subType">String sub-type.</param>
        private void CreateDciStringEntries(int low, int high,
                                            FormatDescriptor.SubType subType)
        {
            int start, end, adj, endMask;

            if (subType == FormatDescriptor.SubType.Dci)
            {
                start = low;
                end   = high + 1;
                adj   = 1;
            }
            else if (subType == FormatDescriptor.SubType.DciReverse)
            {
                start = high;
                end   = low - 1;
                adj   = -1;
            }
            else
            {
                Debug.Assert(false);
                return;
            }

            // Zero-length strings aren't a thing for DCI.  The analyzer requires that all
            // strings in a region have the same polarity, so just grab the last byte.
            endMask = mFileData[end - 1] & 0x80;

            int stringStart = start;

            for (int i = start; i != end; i += adj)
            {
                byte val = mFileData[i];
                if ((val & 0x80) == endMask)
                {
                    // found the end of a string
                    int length           = (i - stringStart) * adj + 1;
                    FormatDescriptor dfd = FormatDescriptor.Create(length,
                                                                   FormatDescriptor.Type.String, subType);
                    Results.Add(stringStart < i ? stringStart : i, dfd);
                    stringStart = i + adj;
                }
            }

            Debug.Assert(stringStart == end);
        }
Exemple #8
0
        /// <summary>
        /// Creates one or more FormatDescriptor entries for the specified range, adding them
        /// to the Results list.
        /// </summary>
        /// <param name="low">Offset of first byte in range.</param>
        /// <param name="high">Offset of last byte in range.</param>
        /// <param name="subType">String sub-type.</param>
        private void CreateCStringEntries(int low, int high,
                                          FormatDescriptor.SubType subType)
        {
            int startOffset = low;

            for (int i = low; i <= high; i++)
            {
                if (mFileData[i] == 0x00)
                {
                    // End of string.  Zero-length strings are allowed.
                    FormatDescriptor dfd = FormatDescriptor.Create(
                        i - startOffset + 1, FormatDescriptor.Type.String, subType);
                    Results.Add(startOffset, dfd);
                    startOffset = i + 1;
                }
                else
                {
                    // keep going
                }
            }

            // Earlier analysis guaranteed that the last byte in the buffer is 0x00.
            Debug.Assert(startOffset == high + 1);
        }
        private void GenerateFormats(int div, int highConst, int bankConst)
        {
            SortedList <int, FormatDescriptor> newDfds   = new SortedList <int, FormatDescriptor>();
            Dictionary <int, Symbol>           newLabels = new Dictionary <int, Symbol>();
            List <int> targetOffsets = new List <int>();
            bool       isBigEndian;

            // Identify the offset where each set of data starts.
            int span = mSelection.Count / div;
            int lowOff, highOff, bankOff;
            int stride;

            if (lowFirstPartRadio.IsChecked == true)
            {
                lowOff      = 0;
                isBigEndian = false;
            }
            else if (lowSecondPartRadio.IsChecked == true)
            {
                lowOff      = 1;
                isBigEndian = true;
            }
            else if (lowThirdPartRadio.IsChecked == true)
            {
                lowOff      = 2;
                isBigEndian = true;
            }
            else
            {
                Debug.Assert(false);
                lowOff      = -1;
                isBigEndian = false;
            }
            if (highFirstPartRadio.IsChecked == true)
            {
                highOff = 0;
            }
            else if (highSecondPartRadio.IsChecked == true)
            {
                highOff = 1;
            }
            else if (highThirdPartRadio.IsChecked == true)
            {
                highOff = 2;
            }
            else
            {
                highOff = -1;   // use constant
            }
            if (width24Radio.IsChecked == true)
            {
                if (bankNthPartRadio.IsChecked == true)
                {
                    // Use whichever part isn't being used by the other two.
                    if (lowOff != 0 && highOff != 0)
                    {
                        bankOff = 0;
                    }
                    else if (lowOff != 1 && highOff != 1)
                    {
                        bankOff = 1;
                    }
                    else
                    {
                        Debug.Assert(lowOff != 2 && highOff != 2);
                        bankOff = 2;
                    }
                }
                else
                {
                    bankOff = -1;   // use constant
                }
            }
            else
            {
                bankOff   = -1;     // use constant
                bankConst = 0;      // always bank 0
            }

            if (IsSplitTable)
            {
                // Split table, so stride is 1 and each section start is determined by the span.
                stride   = 1;
                lowOff  *= span;
                highOff *= span;
                bankOff *= span;
            }
            else
            {
                // For non-split table, the stride is the width of each entry.
                stride = 1;
                if (highOff >= 0)
                {
                    stride++;
                }
                if (bankOff >= 0)
                {
                    stride++;
                }
            }

            Debug.WriteLine("FormatAddressTable: stride=" + stride + " span=" + span +
                            " count=" + mSelection.Count);
            Debug.WriteLine("  low=" + lowOff + " high=" + highOff + " bank=" + bankOff);

            // The TypedRangeSet doesn't have an index operation, so copy the values into
            // an array.
            int[] offsets = new int[mSelection.Count];
            int   index   = 0;

            foreach (TypedRangeSet.Tuple tup in mSelection)
            {
                offsets[index++] = tup.Value;
            }

            int adj = 0;

            if (IsAdjustedForReturn)
            {
                adj = 1;
            }

            // Walk through the file data, generating addresses as we go.
            byte[] fileData = mProject.FileData;
            for (int i = 0; i < span; i++)
            {
                byte low, high, bank;

                low = fileData[offsets[lowOff + i * stride]];
                if (highOff >= 0)
                {
                    high = fileData[offsets[highOff + i * stride]];
                }
                else
                {
                    high = (byte)highConst;
                }
                if (bankOff >= 0)
                {
                    bank = fileData[offsets[bankOff + i * stride]];
                }
                else
                {
                    bank = (byte)bankConst;
                }

                int addr = ((bank << 16) | (high << 8) | low) + adj;

                int targetOffset = mProject.AddrMap.AddressToOffset(offsets[0], addr);
                if (targetOffset < 0)
                {
                    // Address not within file bounds.
                    // TODO(maybe): look for matching platform/project symbols
                    AddPreviewItem(addr, -1, Res.Strings.INVALID_ADDRESS);
                }
                else
                {
                    // Note the same target offset may appear more than once.
                    targetOffsets.Add(targetOffset);

                    // If there's a user-defined label there already, use it.  Otherwise, we'll
                    // need to generate one.
                    string targetLabel;
                    if (mProject.UserLabels.TryGetValue(targetOffset, out Symbol sym))
                    {
                        targetLabel = sym.Label;
                        AddPreviewItem(addr, targetOffset, targetLabel);
                    }
                    else
                    {
                        // Generate a symbol that's unique vs. the symbol table.  We don't need
                        // it to be unique vs. the labels we're generating here, because we
                        // won't generate identical labels for different addresses, and we do
                        // want to generate a single label if more than one table entry refers
                        // to the same target.
                        Symbol tmpSym = AutoLabel.GenerateUniqueForAddress(addr,
                                                                           mProject.SymbolTable, "T");
                        // tmpSym was returned as an auto-label, make it a user label instead
                        // (with global scope)
                        tmpSym = new Symbol(tmpSym.Label, tmpSym.Value, Symbol.Source.User,
                                            Symbol.Type.GlobalAddr, Symbol.LabelAnnotation.Generated);
                        newLabels[targetOffset] = tmpSym;       // overwrites previous
                        targetLabel             = tmpSym.Label;
                        AddPreviewItem(addr, targetOffset, "(+) " + targetLabel);
                    }

                    if (IsSplitTable)
                    {
                        // Now we need to create format descriptors for the addresses where we
                        // extracted the low, high, and bank values.
                        newDfds.Add(offsets[lowOff + i * stride], FormatDescriptor.Create(1,
                                                                                          new WeakSymbolRef(targetLabel, WeakSymbolRef.Part.Low), false));
                        if (highOff >= 0)
                        {
                            newDfds.Add(offsets[highOff + i * stride], FormatDescriptor.Create(1,
                                                                                               new WeakSymbolRef(targetLabel, WeakSymbolRef.Part.High), false));
                        }
                        if (bankOff >= 0)
                        {
                            newDfds.Add(offsets[bankOff + i * stride], FormatDescriptor.Create(1,
                                                                                               new WeakSymbolRef(targetLabel, WeakSymbolRef.Part.Bank), false));
                        }
                    }
                    else
                    {
                        // Create a single format descriptor that spans all bytes.  Note we
                        // don't want to use lowOff here -- we want to put the format on
                        // whichever byte came first.
                        // TODO(maybe): we don't correctly deal with a "scrambled" non-split
                        //   24-bit table, i.e. low then bank then high.  This is not really
                        //   a thing, but we should either prevent it or punt to single-byte
                        //   like we do for split tables.
                        Debug.Assert(stride >= 1 && stride <= 3);
                        newDfds.Add(offsets[0 + i * stride], FormatDescriptor.Create(stride,
                                                                                     new WeakSymbolRef(targetLabel, WeakSymbolRef.Part.Low), isBigEndian));
                    }
                }
            }

            NewFormatDescriptors = newDfds;
            NewUserLabels        = newLabels;
            AllTargetOffsets     = targetOffsets;

            // Don't show ready if all addresses are invalid.  It's okay if some work and
            // some don't.
            mOutputReady = (AllTargetOffsets.Count > 0);
        }
        private void GenerateFormats(int div, int highConst, int bankConst)
        {
            SortedList <int, FormatDescriptor> newDfds   = new SortedList <int, FormatDescriptor>();
            Dictionary <int, Symbol>           newLabels = new Dictionary <int, Symbol>();
            List <int> targetOffsets = new List <int>();

            // Identify the offset where each set of data starts.
            int span = mSelection.Count / div;
            int lowOff, highOff, bankOff;

            if (lowFirstPartRadio.Checked)
            {
                lowOff = 0;
            }
            else if (lowSecondPartRadio.Checked)
            {
                lowOff = span;
            }
            else if (lowThirdPartRadio.Checked)
            {
                lowOff = span * 2;
            }
            else
            {
                Debug.Assert(false);
                lowOff = -1;
            }
            if (highFirstPartRadio.Checked)
            {
                highOff = 0;
            }
            else if (highSecondPartRadio.Checked)
            {
                highOff = span;
            }
            else if (highThirdPartRadio.Checked)
            {
                highOff = span * 2;
            }
            else
            {
                highOff = -1;   // use constant
            }
            if (width24Radio.Checked)
            {
                if (bankNthPartRadio.Checked)
                {
                    // Use whichever part isn't being used by the other two.
                    if (lowOff != 0 && highOff != 0)
                    {
                        bankOff = 0;
                    }
                    else if (lowOff != span && highOff != span)
                    {
                        bankOff = span;
                    }
                    else
                    {
                        Debug.Assert(lowOff != span * 2 && highOff != span * 2);
                        bankOff = span * 2;
                    }
                }
                else
                {
                    bankOff = -1;   // use constant
                }
            }
            else
            {
                bankOff   = -1;     // use constant
                bankConst = 0;      // always bank 0
            }

            Debug.WriteLine("Extract from low=" + lowOff + " high=" + highOff +
                            " bank=" + bankOff);

            // The TypedRangeSet doesn't have an index operation, so copy the values into
            // an array.
            int[] offsets = new int[mSelection.Count];
            int   index   = 0;

            foreach (TypedRangeSet.Tuple tup in mSelection)
            {
                offsets[index++] = tup.Value;
            }

            int adj = 0;

            if (pushRtsCheckBox.Checked)
            {
                adj = 1;
            }

            // Walk through the file data, generating addresses as we go.
            byte[] fileData = mProject.FileData;
            for (int i = 0; i < span; i++)
            {
                byte low, high, bank;

                low = fileData[offsets[lowOff + i]];
                if (highOff >= 0)
                {
                    high = fileData[offsets[highOff + i]];
                }
                else
                {
                    high = (byte)highConst;
                }
                if (bankOff >= 0)
                {
                    bank = fileData[offsets[bankOff + i]];
                }
                else
                {
                    bank = (byte)bankConst;
                }

                int addr = ((bank << 16) | (high << 8) | low) + adj;

                int targetOffset = mProject.AddrMap.AddressToOffset(offsets[0], addr);
                if (targetOffset < 0)
                {
                    // Address not within file bounds.
                    // TODO(maybe): look for matching platform/project symbols
                    AddPreviewItem(addr, -1, Properties.Resources.INVALID_ADDRESS);
                }
                else
                {
                    // Note the same target offset may appear more than once.
                    targetOffsets.Add(targetOffset);

                    // If there's a user-defined label there already, use it.  Otherwise, we'll
                    // need to generate one.
                    string targetLabel;
                    if (mProject.UserLabels.TryGetValue(targetOffset, out Symbol sym))
                    {
                        targetLabel = sym.Label;
                        AddPreviewItem(addr, targetOffset, targetLabel);
                    }
                    else
                    {
                        // Generate a symbol that's unique vs. the symbol table.  We don't need
                        // it to be unique vs. the labels we're generating here, because we
                        // won't generate identical labels for different addresses, and we do
                        // want to generate a single label if more than one table entry refers
                        // to the same target.
                        Symbol tmpSym = SymbolTable.GenerateUniqueForAddress(addr,
                                                                             mProject.SymbolTable, "T");
                        // tmpSym was returned as an auto-label, make it a user label instead
                        tmpSym = new Symbol(tmpSym.Label, tmpSym.Value, Symbol.Source.User,
                                            Symbol.Type.LocalOrGlobalAddr);
                        newLabels[targetOffset] = tmpSym;       // overwrites previous
                        targetLabel             = tmpSym.Label;
                        AddPreviewItem(addr, targetOffset, "(+) " + targetLabel);
                    }

                    // Now we need to create format descriptors for the addresses where we
                    // extracted the low, high, and bank values.
                    newDfds.Add(offsets[lowOff + i], FormatDescriptor.Create(1,
                                                                             new WeakSymbolRef(targetLabel, WeakSymbolRef.Part.Low), false));
                    if (highOff >= 0)
                    {
                        newDfds.Add(offsets[highOff + i], FormatDescriptor.Create(1,
                                                                                  new WeakSymbolRef(targetLabel, WeakSymbolRef.Part.High), false));
                    }
                    if (bankOff >= 0)
                    {
                        newDfds.Add(offsets[bankOff + i], FormatDescriptor.Create(1,
                                                                                  new WeakSymbolRef(targetLabel, WeakSymbolRef.Part.Bank), false));
                    }
                }
            }

            NewFormatDescriptors = newDfds;
            NewUserLabels        = newLabels;
            AllTargetOffsets     = targetOffsets;

            // Don't show ready if all addresses are invalid.
            mOutputReady = (AllTargetOffsets.Count > 0);
        }
Exemple #11
0
        /// <summary>
        /// Creates a FormatDescriptor from the current state of the dialog controls.
        /// </summary>
        /// <returns>New FormatDescriptor.</returns>
        private FormatDescriptor CreateDescriptorFromControls()
        {
            if (radioButtonSymbol.Checked)
            {
                if (string.IsNullOrEmpty(symbolTextBox.Text))
                {
                    // empty symbol --> default format (intuitive way to delete label reference)
                    return(null);
                }
                WeakSymbolRef.Part part;
                if (radioButtonLow.Checked)
                {
                    part = WeakSymbolRef.Part.Low;
                }
                else if (radioButtonHigh.Checked)
                {
                    part = WeakSymbolRef.Part.High;
                }
                else if (radioButtonBank.Checked)
                {
                    part = WeakSymbolRef.Part.Bank;
                }
                else
                {
                    Debug.Assert(false);
                    part = WeakSymbolRef.Part.Low;
                }
                return(FormatDescriptor.Create(mInstructionLength,
                                               new WeakSymbolRef(symbolTextBox.Text, part), false));
            }

            FormatDescriptor.SubType subType;
            if (radioButtonDefault.Checked)
            {
                return(null);
            }
            else if (radioButtonHex.Checked)
            {
                subType = FormatDescriptor.SubType.Hex;
            }
            else if (radioButtonDecimal.Checked)
            {
                subType = FormatDescriptor.SubType.Decimal;
            }
            else if (radioButtonBinary.Checked)
            {
                subType = FormatDescriptor.SubType.Binary;
            }
            else if (radioButtonAscii.Checked)
            {
                subType = FormatDescriptor.SubType.Ascii;
            }
            else if (radioButtonSymbol.Checked)
            {
                subType = FormatDescriptor.SubType.Symbol;
            }
            else
            {
                Debug.Assert(false);
                subType = FormatDescriptor.SubType.None;
            }

            return(FormatDescriptor.Create(mInstructionLength,
                                           FormatDescriptor.Type.NumericLE, subType));
        }