summaryrefslogtreecommitdiff
path: root/util/gdbinit
blob: ff71e4c39c1fd1bf108a4df64da02a7d27d53be1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# Copyright 2019 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# This file is intended to be used as a .gdbinit for an EC debugging session.
# It defines some useful functions for analyzing the EC state.
#
# Setup Automatic Import:
# ln -s util/gdbinit .gdbinit
#
# Environment Variables:
# BOARD=[nocturne_fp|bloonchipper|...]
# GDBSERVER=[segger|openocd]
# GDBPORT=[gdb-server-port-number]
#
# Warning, this is a working collection that is not guaranteed to function
# properly on all platforms. The ec-tasks functions is a good example of a
# function that works well on most simple platforms, but may have issues on
# platforms with data cache enabled.
#
# Note, this file must maintain space indention to allow easy copy/paste
# while in active debugging. Using tabs interferes with the embedded python
# during copy/paste.

#####################################################################
# Environment Setup and Initialization                              #
#####################################################################

set verbose on

# Start of python code

# Setup environment and pull in object files for the particular BOARD.
# This requires setting the environment variables mentioned above.
python
import distutils.util
import os

BOARD = os.getenv('BOARD', '')
GDBSERVER = os.getenv('GDBSERVER', 'openocd')
USING_CLION = distutils.util.strtobool(os.getenv('USING_CLION', 'FALSE'))
# BIN_NAME can be changed to be the name of a unit test, such as "sha256"
BIN_NAME = os.getenv('BIN_NAME', 'ec')

BIN_DIR = ''
if BIN_NAME != 'ec':
  BIN_DIR = BIN_NAME

if GDBSERVER == "openocd":
    DEFAULT_GDB_PORT = '3333'
else:
    DEFAULT_GDB_PORT = '2331'

GDBPORT = os.getenv('GDBPORT', DEFAULT_GDB_PORT)

EC_DIR = os.getenv('EC_DIR', os.path.join(os.getenv('HOME'),
                   'chromiumos/src/platform/ec'))

if not os.path.isdir(EC_DIR):
    print('Error - EC_DIR "' + EC_DIR + '" doesn\'t exist. Aborting.')
    gdb.execute('quit')

# Monitor commands must be run after connecting to the remote target
# See https://stackoverflow.com/a/39828850
# https://youtrack.jetbrains.com/issue/CPP-7322
# https://sourceware.org/gdb/onlinedocs/gdb/Hooks.html
post_remote_hook='''
define target hookpost-remote
    echo \ Flashing EC binary
    load {EC_DIR}/build/{BOARD}/{BIN_DIR}/{BIN_NAME}.obj
    echo \ Resetting target
    monitor reset
    echo \ Setting breakpoint on main
    b main
end\n
'''.format(BOARD=BOARD, EC_DIR=EC_DIR, BIN_DIR=BIN_DIR, BIN_NAME=BIN_NAME)

gdb.execute('set $BOARD = "%s"'%BOARD)
gdb.execute('set $GDBSERVER = "%s"'%GDBSERVER)
gdb.execute('set $GDBPORT = "%s"'%GDBPORT)

build = os.path.join(EC_DIR, 'build', BOARD)
if BOARD != "":
    if not os.path.isdir(build):
        print('Error - Build path "' + build + '" doesn\'t exist. Aborting.')
        gdb.execute('quit')

    # When using gdb from CLion, this kills gdb.
    if not USING_CLION:
        gdb.execute('file ' + os.path.join(build, 'ec.obj'))
    gdb.execute('add-symbol-file ' + os.path.join(build, BIN_DIR, 'RO', BIN_NAME + '.RO.elf'))
    gdb.execute('add-symbol-file ' + os.path.join(build, BIN_DIR, 'RW', BIN_NAME + '.RW.elf'))

if GDBSERVER == "openocd":
    gdb.execute('set $GDBSERVER_OPENOCD = 1')
    gdb.execute('set $GDBSERVER_SEGGER = 0')
elif GDBSERVER == "segger":
    gdb.execute('set $GDBSERVER_OPENOCD = 0')
    gdb.execute('set $GDBSERVER_SEGGER = 1')
    gdb.execute(post_remote_hook)
else:
    print('Error - GDBSERVER="' + GDBSERVER + '" is invalid.')
    gdb.execute('quit')

# End of python code
end

# OpenOCD specific config
if $GDBSERVER_OPENOCD
    # Don't auto choose hw/sw breakpoints from memory-map
    set breakpoint auto-hw off
end

# Segger specific config
if $GDBSERVER_SEGGER
    # If enabled, disable flash breakpoints.
    #monitor flash breakpoints = 0
end

# If enabled, force breakpoints to be inserted at all times.
# They will not be reinserted on reconnects.
#set breakpoint always-inserted on

#####################################################################
# Helper Functions                                                  #
#####################################################################

# Usage: ec-reg32 <address> [offset]
# Read a 32 bit register
define ec-reg32
    set $a = $arg0
    if $argc > 1
        set $a += $arg1
    end
    set $v = *((uint32_t *)$a)
    print $v
    print /x $v
    print /t $v
end
alias reg32 = ec-reg32

# Usage: ec-connect
# Issue the overly long target connect command using the
# specified gdb server port.
define ec-connect
python
# May want to only use "target remote".
gdb.execute(f'target extended-remote :{GDBPORT}')
end
end
alias connect = ec-connect

# Usage: ec-reset
# Issue the reset sequence for the debugger to halt on boot.
define ec-reset
    if $GDBSERVER_OPENOCD
        monitor halt
        monitor reset halt
    else
        monitor halt
        monitor reset
    end
end
alias reset = ec-reset

# Usage: ec-tasks
# Prints out information about current EC task set and tries to determine
# if the task's stack has been overrun.
# This function may not work properly if MCU data cache is enabled.
define ec-tasks
    set $taskid_cur = current_task - tasks
    set $id = 0
    set $taskcount = sizeof(tasks)/sizeof(tasks[0])
    printf "Task Ready Name         Events      Time (s)  StkUsed\n"
    while $id < $taskcount
        set $is_ready = (tasks_ready & (1<<$id)) ? 'R' : ' '
        set $unused = (uint32_t)0xdeadd00d
        set $stacksize = tasks_init[$id].stack_size
        set $stackused = $stacksize
        set $s = tasks[$id].stack
        while $s < (uint32_t *)tasks[$id].sp && *$s == $unused
            set $stackused -= sizeof(uint32_t)
            set $s++
        end
        printf "%4d %-5c %-16s %08x %11.6ld  %3d/%3d", $id, $is_ready,  task_names[$id], tasks[$id].events, tasks[$id].runtime, $stackused, tasks_init[$id].stack_size
        if $stackused == $stacksize
            printf "\t [overrun]"
        end
        if $id == $taskid_cur
            printf "\t*"
        end
        printf "\n"
        set $id++
    end
    if $taskid_cur == scratchpad
        printf "Current task is set to scratchpad\n"
    end
end

# Usage: ec-stayro
# Adds magic breakpoint that changes the outcome of the RW signature
# validation step that forces the MCU to stay in the RO section.
# This function needs improvements to not be dependent on line numbers.
define ec-stayro
    break common/rwsig.c:282
    commands
        set evt = 1
        printf "Continuing as RO\n"
        continue
    end
end

# Usage: ec-brexception
# Set breakpoints on EC exception handlers.
define ec-brexception
    break exception_panic
    break bus_fault_handler
    break panic_assert_fail
end