############################################################################
# tools/esp32/backtrace.gdbscript
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.  The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
# License for the specific language governing permissions and limitations
# under the License.
#
############################################################################

# Usage:
#
#       (gdb) esp32_bt <pc> <return address (a0)> <sp (a1)>
#
# Example 1:
#
#   -------
#       xtensa_btdump: Backtrace0: 400d82a3:3ffdec60
#       xtensa_btdump: Backtrace1: 400d82ff:3ffdec80
#   -------
#       (gdb) esp32_bt 0x400d82ff 0x400d82a3 0x3ffdec60
#   -------
#
# Example 2:
#
#   -------
#       xtensa_registerdump:    PC: 400d5775    PS: 00060e33
#       xtensa_registerdump:    A0: 800d504c    A1: 3ffd8080    A2: 3ffdfb28    A3: 00000001
#   -------
#       (gdb) esp32_bt 0x400d5775 0x800d504c 0x3ffd8080
#   -------
#
# Caveats:
#
#   This doesn't work if the specified register values are already
#   inconsistent with the frames on the stack. It's usually the case
#   when xtensa_registerdump saved the state by itself using
#   xtensa_context_save.
#
# References:
#
#   Xtensa(R) Instruction Set Architecture (ISA) Reference Manual
#   4.7.1.4 Call, Entry, and Return Mechanism
#   4.7.1.5 Windowed Procedure-Call Protocol

define esp32_bt
    set $pc = $arg0
    set $a0 = $arg1
    set $a1 = $arg2
    set $pc_topbits = (int)$pc & 0xc0000000
    # The return address from xtensa_sig_deliver to _xtensa_sig_trampoline
    set $sig_tramp_ra = (int)(_xtensa_sig_trampoline + 2 * 3)
    print/a $pc
    while (1)
        # Note: "- 3" to workaround the case where "call" is
        # the last instruction in the calling function.
        set $next_pc = (($a0 & 0x3fffffff) | $pc_topbits) - 3
        print/a $next_pc
        if ($a0 == $sig_tramp_ra)
            # A special logic for xtensa_sig_deliver

            print "--- SIGNAL ---"

            # XXX SMP
            set $tcb = (struct tcb_s *)g_readytorun.head
            set $next_pc = $tcb.xcp.saved_pc
            print/a $next_pc

            # XXX local var offset assumption
            set $regs = (int *)$a1

            # Note: REG_A0 == 2
            # Note: REG_A1 == 3
            set $next_a0 = $regs[2]
            set $next_a1 = $regs[3]
        else
            set $next_bsa = (int *)($a1 - 16)
            set $next_a0 = $next_bsa[0]
            set $next_a1 = $next_bsa[1]
        end
        if ($next_a0 == 0)
            # Xtensa(R) Instruction Set Architecture (ISA) Reference Manual
            # 8.1.9 Stack Initialization
            # "The return address register (a0) for the first procedure
            # on the stack must be explicitly set to zero."
            loop_break
        end
        if ($next_a1 <= $a1)
            print "stack went backward. corrupted?"
            loop_break
        end
        set $a0 = $next_a0
        set $a1 = $next_a1
    end
end