예제 #1
0
        void GetStackTrace(Request request)
        {
            _session.Machine.Registers.Read();

            if (_session.Machine.Memory.ReadConfiguration())
            {
                _session.Machine.Memory.Log();
            }

            // disassemble from current PC
            var disassemblyUpdated = _session.Machine.UpdateDisassembly(_session.Machine.Registers.PC);

            var originBytes = new byte[4];

            _stackInfo.Clear();
            _stackFrames.Clear();

            // add current PC as an entry to the stack frame
            _stackInfo.Add(new StackInfo(_session.Machine.Registers.PC));

            var stackPos = _session.Machine.Registers.SP;

            // read bytes from SP onwards for analysis of the addresses
            var stackBytes = new byte[20];
            var maxBytes   = Math.Min(stackBytes.Length, 0xFFFF - stackPos);
            var bytes      = _session.Machine.Memory.Read(_session.Machine.Registers.SP, stackBytes, 0, maxBytes);

            // turn the bytes into ushorts
            for (var i = 0; i < bytes; i += 2)
            {
                _stackInfo.Add(new StackInfo((ushort)((stackBytes[i + 1] << 8) | stackBytes[i])));
            }

            // now check out each address
            for (var i = 0; i < _stackInfo.Count; i++)
            {
                // note: entry at i=0 is PC, so we don't need to get mem and we always show it

                var stackFrameId = i + 1;
                var addr         = _stackInfo[i].Address;

                AddressDetails addressDetails = null;
                bool           isCode         = false;

                var symbolIcon = "";

                if (i == 0)
                {
                    // always try to get symbol for PC
                    addressDetails = _session.Machine.GetAddressDetails(addr);
                    isCode         = true;
                }
                else
                {
                    _session.Machine.Memory.Read((ushort)(addr - 3), originBytes, 0, 3);

                    if (_callerOpcode3.Contains(originBytes[0]))
                    {
                        addr          -= 3;
                        addressDetails = _session.Machine.GetAddressDetails(addr);
                        isCode         = true;
                        symbolIcon     = " ↑";

                        // // we can get the original destination for the call here:
                        // var callDest = (ushort) ( caller[2] << 8 | caller[1] );
                        // var callDestSymbol = GetPreviousSymbol( callDest, ref disassemblyUpdated );
                        // if( callDestSymbol != null )
                        // {
                        //     if( _stackFrames.Count > 0 )
                        //         _stackFrames[_stackFrames.Count - 1].name = callDestSymbol + " -> " + _stackFrames[_stackFrames.Count - 1].name;
                        // }
                    }
                    else if (_callerOpcode3.Contains(originBytes[1]))
                    {
                        addr          -= 2;
                        addressDetails = _session.Machine.GetAddressDetails(addr);
                        isCode         = true;
                    }
                    else if (_callerOpcode1.Contains(originBytes[2]))
                    {
                        addr          -= 1;
                        addressDetails = _session.Machine.GetAddressDetails(addr);
                        isCode         = true;
                        symbolIcon    += " ↖";
                    }

                    _stackInfo[i].Address = addr;
                }

                if (addressDetails?.Labels != null && addressDetails.LabelledAddress != addressDetails.Address)
                {
                    disassemblyUpdated |= _session.Machine.UpdateDisassembly(addressDetails.LabelledAddress);
                }

                var style = i == 0 ? "subtle" : "normal";

                var text = addressDetails?.Labels?[0].Name ?? addr.ToHex();

                if (addressDetails?.Source != null)
                {
                    // got source
                    // highlight the source line separately
                    // we always trace through the disassembly

                    _stackInfo[i].SourceFilename = addressDetails.Source.File.Filename;
                    _stackInfo[i].SourceLine     = addressDetails.Source.Line;
                }

                if (addressDetails != null)
                {
                    // no source, but probably labels

                    _stackFrames.Add(
                        new StackFrame(
                            stackFrameId,
                            addressDetails.GetRelativeText() + " " + symbolIcon,
                            DisassemblySource,
                            0,
                            0,
                            style
                            )
                        );
                }
                else if (isCode)
                {
                    // no labels, but it's code

                    _stackFrames.Add(
                        new StackFrame(
                            stackFrameId,
                            text + " " + symbolIcon,
                            DisassemblySource,
                            0,
                            0,
                            style
                            )
                        );
                }
                else
                {
                    // not code, just a raw value

                    _stackFrames.Add(
                        new StackFrame(
                            stackFrameId,
                            addr.ToHex(),
                            StackSource,
                            0,
                            0,
                            style
                            )
                        );
                }
            }

            if (disassemblyUpdated)
            {
                _session.Machine.WriteDisassemblyFile(DisassemblyFile);
            }

            foreach (var frame in _stackFrames)
            {
                if (frame.source == DisassemblySource && frame.line == 0)
                {
                    frame.line = _session.Machine.GetLineOfAddressInDisassembly(_stackInfo[frame.id - 1].Address) + 1;
                }
            }

            _session.VSCode.Send(
                request,
                new StackTraceResponseBody(
                    _stackFrames
                    )
                );

            foreach (var m in _memWatches)
            {
                Check_MemoryWatch(m.Value);
            }
        }