openocd: fix SPDX tag format for files .c
[fw/openocd] / src / target / trace.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4  *   Copyright (C) 2005, 2007 by Dominic Rath                              *
5  *   Dominic.Rath@gmx.de                                                   *
6  ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <helper/log.h>
13 #include "trace.h"
14 #include "target.h"
15
16 int trace_point(struct target *target, uint32_t number)
17 {
18         struct trace *trace = target->trace_info;
19
20         LOG_DEBUG("tracepoint: %i", (int)number);
21
22         if (number < trace->num_trace_points)
23                 trace->trace_points[number].hit_counter++;
24
25         if (trace->trace_history_size) {
26                 trace->trace_history[trace->trace_history_pos++] = number;
27                 if (trace->trace_history_pos == trace->trace_history_size) {
28                         trace->trace_history_pos = 0;
29                         trace->trace_history_overflowed = 1;
30                 }
31         }
32
33         return ERROR_OK;
34 }
35
36 COMMAND_HANDLER(handle_trace_point_command)
37 {
38         struct target *target = get_current_target(CMD_CTX);
39         struct trace *trace = target->trace_info;
40
41         if (CMD_ARGC == 0) {
42                 uint32_t i;
43
44                 for (i = 0; i < trace->num_trace_points; i++) {
45                         command_print(CMD, "trace point 0x%8.8" PRIx32 " (%lld times hit)",
46                                         trace->trace_points[i].address,
47                                         (long long)trace->trace_points[i].hit_counter);
48                 }
49
50                 return ERROR_OK;
51         }
52
53         if (!strcmp(CMD_ARGV[0], "clear")) {
54                 free(trace->trace_points);
55                 trace->trace_points = NULL;
56
57                 trace->num_trace_points = 0;
58                 trace->trace_points_size = 0;
59
60                 return ERROR_OK;
61         }
62
63         /* resize array if necessary */
64         if (!trace->trace_points || (trace->trace_points_size == trace->num_trace_points)) {
65                 trace->trace_points = realloc(trace->trace_points,
66                                 sizeof(struct trace_point) * (trace->trace_points_size + 32));
67                 trace->trace_points_size += 32;
68         }
69
70         uint32_t address;
71         COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
72         trace->trace_points[trace->num_trace_points].address = address;
73         trace->trace_points[trace->num_trace_points].hit_counter = 0;
74         trace->num_trace_points++;
75
76         return ERROR_OK;
77 }
78
79 COMMAND_HANDLER(handle_trace_history_command)
80 {
81         struct target *target = get_current_target(CMD_CTX);
82         struct trace *trace = target->trace_info;
83
84         if (CMD_ARGC > 0) {
85                 trace->trace_history_pos = 0;
86                 trace->trace_history_overflowed = 0;
87
88                 if (!strcmp(CMD_ARGV[0], "clear")) {
89                         /* clearing is implicit, we've just reset position anyway */
90                         return ERROR_OK;
91                 }
92
93                 free(trace->trace_history);
94
95                 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], trace->trace_history_size);
96                 trace->trace_history = malloc(sizeof(uint32_t) * trace->trace_history_size);
97
98                 command_print(CMD, "new trace history size: %i", (int)(trace->trace_history_size));
99         } else {
100                 uint32_t i;
101                 uint32_t first = 0;
102                 uint32_t last = trace->trace_history_pos;
103
104                 if (!trace->trace_history_size) {
105                         command_print(CMD, "trace history buffer is not allocated");
106                         return ERROR_OK;
107                 }
108
109                 if (trace->trace_history_overflowed) {
110                         first = trace->trace_history_pos;
111                         last = trace->trace_history_pos - 1;
112                 }
113
114                 for (i = first; (i % trace->trace_history_size) != last; i++) {
115                         if (trace->trace_history[i % trace->trace_history_size] < trace->num_trace_points) {
116                                 uint32_t address;
117                                 address = trace->trace_points[trace->trace_history[i % trace->trace_history_size]].address;
118                                 command_print(CMD, "trace point %i: 0x%8.8" PRIx32 "",
119                                                 (int)(trace->trace_history[i % trace->trace_history_size]),
120                                                 address);
121                         } else
122                                 command_print(CMD, "trace point %i: -not defined-",
123                                                 (int)(trace->trace_history[i % trace->trace_history_size]));
124                 }
125         }
126
127         return ERROR_OK;
128 }
129
130 static const struct command_registration trace_exec_command_handlers[] = {
131         {
132                 .name = "history",
133                 .handler = handle_trace_history_command,
134                 .mode = COMMAND_EXEC,
135                 .help = "display trace history, clear history or set size",
136                 .usage = "['clear'|size]",
137         },
138         {
139                 .name = "point",
140                 .handler = handle_trace_point_command,
141                 .mode = COMMAND_EXEC,
142                 .help = "display trace points, clear list of trace points, "
143                         "or add new tracepoint at address",
144                 .usage = "['clear'|address]",
145         },
146         COMMAND_REGISTRATION_DONE
147 };
148 static const struct command_registration trace_command_handlers[] = {
149         {
150                 .name = "trace",
151                 .mode = COMMAND_EXEC,
152                 .help = "trace command group",
153                 .usage = "",
154                 .chain = trace_exec_command_handlers,
155         },
156         COMMAND_REGISTRATION_DONE
157 };
158
159 int trace_register_commands(struct command_context *cmd_ctx)
160 {
161         return register_commands(cmd_ctx, NULL, trace_command_handlers);
162 }