From 334552bc831baf4a88f8b42c93e87ed052c923d2 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Mon, 22 Oct 2018 09:06:50 +0200 Subject: [PATCH] helper/startup.tcl: fix execution stack frame of wrapped commands The OpenOCD commands that have been wrapped with 'ocd_bouncer' are executed within two levels of nested proc's: # see register_command_handler() in src/helper/command.c proc my_command {args} {eval ocd_bouncer my_command $args} # see ocd_bouncer in src/helper/startup.tcl proc ocd_bouncer {name args} { ... [eval ocd_my_command $args] ... } This causes the stack frame of 'ocd_my_command' to be the same one of proc 'ocd_bouncer', thus two levels below the stack frame of the caller of 'my_command'. This is an issue with commands that receive a variable by name and have to resolve them to access the value. E.g. the command mem2array arrayname bitwidth address count is wrapped; it receives the name of the array but fails to resolve it in the current stack frame. Instead, the commands mem2array arrayname bitwidth address count ocd_ mem2array arrayname bitwidth address count are not wrapped and can directly access the array because they share the same stack frame of the caller. Same situation with the symmetric commands 'array2mem'. How to test: within a telnet connection, run the following set of commands, eventually replacing the address 0x08000000 with a valid readable address of your , unset -nocomplain v1 v2 v3 info vars v? mem2array v1 32 0x08000000 1 mem2array v2 32 0x08000000 1 ocd_ mem2array v3 32 0x08000000 1 info vars v? and notice that only v1 and v3 are now allocated. The array v2 has been allocated in the temporarily stack frame of proc ocd_bouncer, together with its local variables, and then lost when proc ended. Fixed by executing the wrapped commands with the command 'uplevel' instead of 'eval'. The amount of levels to skip is checked to avoid errors in the unusual case 'ocd_bouncer' is called directly without the first level of wrapper. Change-Id: Iff90fb8921faf9b5ab04f61062a530578cc20d78 Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/4731 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Tomas Vanek --- src/helper/startup.tcl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/helper/startup.tcl b/src/helper/startup.tcl index 4ca2cabc26..2578de9306 100644 --- a/src/helper/startup.tcl +++ b/src/helper/startup.tcl @@ -12,15 +12,18 @@ proc exit {} { # All commands are registered with an 'ocd_' prefix, while the "real" # command is a wrapper that calls this function. Its primary purpose is -# to discard 'handler' command output, +# to discard 'handler' command output. +# Due to the two nested proc calls, this wrapper has to explicitly run +# the wrapped command in the stack frame two levels above. proc ocd_bouncer {name args} { set cmd [format "ocd_%s" $name] set type [eval ocd_command type $cmd $args] set errcode error + set skiplevel [expr [eval info level] > 1 ? 2 : 1] if {$type == "native"} { - return [eval $cmd $args] + return [uplevel $skiplevel $cmd $args] } else {if {$type == "simple"} { - set errcode [catch {eval $cmd $args}] + set errcode [catch {uplevel $skiplevel $cmd $args}] if {$errcode == 0} { return "" } else { -- 2.30.2