0%

OpenOCD 实用方法

OpenOCD 的一些实用方法。

Flash Commands

Referencd openocd.pdf

1
flash write_image [erase] [unlock] filename [offset] [type]

Write the image filename to the current target’s flash bank(s). Only loadable sections from the image are written. A relocation offset may be specified, in which case it is added to the base address for each section in the image. The file [type] can be specified explicitly as bin (binary), ihex (Intel hex), elf (ELF file), s19 (Motorola s19). mem, or builder. The relevant flash sectors will be erased prior to programming if the erase parameter is given. If unlock is provided, then the flash banks are unlocked before erase and program. The flash bank to use is inferred from the address of each image section.

Warning: Be careful using the erase flag when the flash is holding data you want to preserve. Portions of the flash outside those described in the image’s sections might be erased with no notice.

  • When a section of the image being written does not fill out all the sectors it uses, the unwritten parts of those sectors are necessarily also erased, because sectors can’t be partially erased.
  • Data stored in sector “holes” between image sections are also af- fected. For example, “flash write_image erase …” of an image with one byte at the beginning of a flash bank and one byte at the end erases the entire bank – not just the two sectors being written.

Also, when flash protection is important, you must re-apply it after it has been removed by the unlock flag.

Image loading commands

1
dump_image filename address size

Dump size bytes of target memory starting at address to the binary file named filename.

1
load_image filename address [[bin|ihex|elf|s19] min_addr max_length]

Load image from file filename to target memory offset by address from its load address. The file format may optionally be specified (bin, ihex, elf, or s19). In addition the following arguments may be specifed: min addr - ignore data below min addr (this is w.r.t. to the target’s load address + address) max length - maximum number of bytes to load.

1
2
3
4
5
proc load_image_bin {fname foffset address length } { 
# Load data from fname filename at foffset offset to
# target at address. Load at most length bytes.
load_image $fname [expr $address - $foffset] bin $address $length
}

Breakpoint and Watchpoint commands

CPUs often make debug modules accessible through JTAG, with hardware support for a handful of code breakpoints and data watchpoints. In addition, CPUs almost always support software breakpoints.

1
bp [address len [hw]]

With no parameters, lists all active breakpoints. Else sets a breakpoint on code execution starting at address for length bytes. This is a software breakpoint, unless hw is specified in which case it will be a hardware breakpoint. (See [arm9 vector catch], page 117, or see [xscale vector catch], page 120, for similar mechanisms that do not consume hardware breakpoints.)

1
rbp address

Remove the breakpoint at address.

1
rwp address 

Remove data watchpoint on address

1
wp [address len [(r|w|a) [value [mask]]]]

With no parameters, lists all active watchpoints. Else sets a data watchpoint on data from address for length bytes. The watch point is an “access” watchpoint unless the r or w parameter is provided, defining it as respectively a read or write watchpoint. If a value is provided, that value is used when determining if the watchpoint should trigger. The value may be first be masked using mask to mark “don’t care” fields.

TCP/IP Ports

The OpenOCD server accepts remote commands in several syntaxes. Each syntax uses a different TCP/IP port, which you may specify only during configuration (before those ports are opened).

For reasons including security, you may wish to prevent remote access using one or more of these ports. In such cases, just specify the relevant port number as “disabled”. If you disable all access through TCP/IP, you will need to use the command line -pipe option.

OpenOCD 默认会起三个 tcp server:gdb_port,tcl_port 和 telnet_port,默认端口分别为:3333,4444,6666。若不想开启某个 tcp server,指定其端口号为 disabled 即可。

1
2
3
gdb_port [number]
tcl_port [number]
telnet_port [number]

对于连接了多个 J-Link 的情况,OpenOCD 提供了一个命令 jlink serial [number] 来指定其中一个。

但是 OpenOCD 没有提供查询 J-Link SN 的指令,这就需要我们自己来实现了。

参考源码中 jlink_init 函数中对 J-Link serial 查询的那部分代码,对 jlink_serial_command 函数进行改造:

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
COMMAND_HANDLER(jlink_serial_command)
{
int ret;
struct jaylink_device **devs;
unsigned int i;
uint32_t tmp;
enum jaylink_usb_address address;
size_t num_devices;
uint32_t host_interfaces;
struct jaylink_context *_jayctx;

if (CMD_ARGC == 0) {
LOG_DEBUG("Using libjaylink %s (compiled with %s).",
jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING);

if (!jaylink_library_has_cap(JAYLINK_CAP_HIF_USB) && use_usb_address) {
LOG_ERROR("J-Link driver does not support USB devices.");
return ERROR_JTAG_INIT_FAILED;
}

ret = jaylink_init(&_jayctx);

if (ret != JAYLINK_OK) {
LOG_ERROR("jaylink_init() failed: %s.", jaylink_strerror(ret));
return ERROR_JTAG_INIT_FAILED;
}

host_interfaces = JAYLINK_HIF_USB;

if (use_serial_number)
host_interfaces |= JAYLINK_HIF_TCP;

ret = jaylink_discovery_scan(_jayctx, host_interfaces);

if (ret != JAYLINK_OK) {
LOG_ERROR("jaylink_discovery_scan() failed: %s.",
jaylink_strerror(ret));
jaylink_exit(_jayctx);
return ERROR_JTAG_INIT_FAILED;
}

ret = jaylink_get_devices(_jayctx, &devs, &num_devices);

if (ret != JAYLINK_OK) {
LOG_ERROR("jaylink_get_devices() failed: %s.", jaylink_strerror(ret));
jaylink_exit(_jayctx);
return ERROR_JTAG_INIT_FAILED;
}

for (i = 0; devs[i]; i++) {
ret = jaylink_device_get_serial_number(devs[i], &tmp);

if (ret == JAYLINK_ERR_NOT_AVAILABLE) {
continue;
} else if (ret != JAYLINK_OK) {
LOG_WARNING("jaylink_device_get_serial_number() failed: %s.",
jaylink_strerror(ret));
continue;
}

ret = jaylink_device_get_usb_address(devs[i], &address);

if (ret == JAYLINK_ERR_NOT_SUPPORTED) {
continue;
} else if (ret != JAYLINK_OK) {
LOG_WARNING("jaylink_device_get_usb_address() failed: %s.",
jaylink_strerror(ret));
continue;
}

command_print(CMD_CTX, "Found device %d, SN: %08x, USB address: %d", i, tmp, address);
}

jaylink_exit(_jayctx);

return ERROR_OK;
}

ret = jaylink_parse_serial_number(CMD_ARGV[0], &serial_number);

if (ret == JAYLINK_ERR) {
command_print(CMD_CTX, "Invalid serial number: %s.", CMD_ARGV[0]);
return ERROR_FAIL;
} else if (ret != JAYLINK_OK) {
command_print(CMD_CTX, "jaylink_parse_serial_number() failed: %s.",
jaylink_strerror(ret));
return ERROR_FAIL;
}

use_serial_number = true;
use_usb_address = false;

return ERROR_OK;
}

Make Raspberry Pi as a OpenOCD debugger !!! 🐂

https://blog.csdn.net/wanshiyingg/article/details/52705913

http://blog.sina.com.cn/s/blog_7cedb56d0102v141.html

OpenOCD 在 linux 上的权限问题

https://www.cnblogs.com/jxhd1/p/6528574.html

Permissions delegation

Running OpenOCD with root/administrative permissions is strongly
discouraged for security reasons.

For USB devices on GNU/Linux you should use the contrib/60-openocd.rules
file. It probably belongs somewhere in /etc/udev/rules.d, but
consult your operating system documentation to be sure. Do not forget
to add yourself to the “plugdev” group.

For parallel port adapters on GNU/Linux and FreeBSD please change your
“ppdev” (parport* or ppi*) device node permissions accordingly.

For parport adapters on Windows you need to run install_giveio.bat
(it’s also possible to use “ioperm” with Cygwin instead) to give
ordinary users permissions for accessing the “LPT” registers directly.

重定向 stdout 到 log file

1
2
3
--log_output | -l redirect log output to file <name>
log_output [filename]
Redirect logging to filename; the initial log output channel is stderr.

openocd 提供 -l 来定向 log file,但是 openocd 的输出默认是 stderr,所以 stdout 是没有定向到 log file 内的。

所以还是用 >> 重定向符来把 stdout/err 都定向到 log file 内。

1
2

>> openocd.log 2>&1

hla

hla 是什么?hla_swd 和 swd 有什么区别?

有些调试适配器(STLink, TI ICDI),不开放底层功能,只能使用高层的 API,OpenOCD 为这些适配器定义了一个专有的接口 - High Level Adapters,缩写为 hla。OpenOCD 内这些调试器不能使用诸如 cortex_m 等底层指令。

https://sourceforge.net/p/openocd/mailman/message/33133520/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
On Fri, Nov 21, 2014 at 12:41:30PM -0800, Myles Watson wrote:
> I'd like to disable the debugging mode as part of programming the chip. In
> order to do that, the RESET register in the POWER module needs to be
> written, and then swdioclk and swdio need to be held low for a minimum of
> 100us.
>
> Since the nRF51822 has a shared swdio/nreset line, the reset doesn't work
> if the chip is not returned to normal mode.
>
> Where should I add a "hard-reset" function which is specific to the
> nRF51822 and SWD?

Hi Myles,

Did you have any luck with this? I saw the post when you originally
made it, but I didn't reply as I didn't really have any good ideas -
as far as I know you can't directly control the SWDIO and SWCLK pins
on the STLinkv2 adapter, as it's a "high level adapter" (hla) type and
its protocol doesn't give you that low level of control. :(


Angus

reset halt

reset halt 的效果是是在复位并停在第一条指令,它是原理是什么呢?

arm core从reset state马上转为debug halt state的条件, spec中的说明是:

  1.  寄存器DHCSR.C_DEBUGEN=1, 使能debug
  2.  寄存器DEMCR.VC_CORERESET=1, 可以让触发local reset的时候停在执行第一条指令前
  3.  Trigger reset

注意,拉reset pin进行hw reset对于cm4来说是power-on reset类型, 而armv7m spec是不支持power-on reset halt debug的, power-on reset类型也会将arm debug module也reset了;

所以触发这种reset后, reset前下的halt request就失效了,无法在上电后要执行的第一条halt住,因此就会出现目前你们所遇到的halt timeout问题。

对于armv7m来说,区分两种等级的reset:power-on reset(total reset)和local reset(partial reset) (local reset还可以细分有SYSRSTREQ和VECTRESET)

openocd中触发hw reset也是走这个流程, 但是reset后,debug相关的寄存器(DHCSR, DEMCR)被复位了,

我在openocd中加入一些log抓取了reset前后相关寄存器的变化

Reset前: DHCSR.C_DEBUGEN=1,系统有使能debug;DEMCR.VC_CORERESET=1允许reset后马上进入halt debug状态(这两个值在local reset均不会变化,power-on reset会复位)

Reset后: DHCSR.C_RESET_ST=1,表明系统刚刚有触发了reest,DHCSR.C_DEBUGEN=0,系统没有使能debug;DEMCR.VC_CORERESET=0,这样离开系统后系统无法立即halt住,DHCSR.S_HALT=0,表示系统是处于running状态而不是halt状态。

debug相关寄存器发生了复位,所以是发生了power-on reset,这样我们就没有办法在拉reset pin后马上halt住。

RAM Code

  1. RAM code 不需要加载 .text 和 .data 段,但是必须清零 .bss 段即可。

  2. 使用 load app.elf 命令把 .text 和 .data 段 load 进 RAM 内,并自动设置 PC 的值为 .ld 的 ENTRY 值。

    1
    arm-none-eabi-gdb build/mx1101.elf -ex "target remote localhost:3333" -ex "monitor reset halt" -ex "load build/mx1101.elf" -ex "b main" -ex "layout split" -ex "focus cmd" --tui
坚持原创技术分享,您的支持将鼓励我继续创作!