# Copyright 2019 The ChromiumOS Authors # 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
[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