openocd: fix simple cases of NULL comparison
[fw/openocd] / src / rtos / hwthread.c
1 /***************************************************************************
2  *                                                                         *
3  *   This program is free software; you can redistribute it and/or modify  *
4  *   it under the terms of the GNU General Public License as published by  *
5  *   the Free Software Foundation; either version 2 of the License, or     *
6  *   (at your option) any later version.                                   *
7  *                                                                         *
8  *   This program is distributed in the hope that it will be useful,       *
9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
11  *   GNU General Public License for more details.                          *
12  *                                                                         *
13  *   You should have received a copy of the GNU General Public License     *
14  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
15  ***************************************************************************/
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include <helper/time_support.h>
22 #include <jtag/jtag.h>
23 #include "target/target.h"
24 #include "target/target_type.h"
25 #include "target/register.h"
26 #include "rtos.h"
27 #include "helper/log.h"
28 #include "helper/types.h"
29 #include "server/gdb_server.h"
30
31 static bool hwthread_detect_rtos(struct target *target);
32 static int hwthread_create(struct target *target);
33 static int hwthread_update_threads(struct rtos *rtos);
34 static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
35                 uint32_t reg_num, struct rtos_reg *rtos_reg);
36 static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
37                 struct rtos_reg **reg_list, int *num_regs);
38 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
39 static int hwthread_smp_init(struct target *target);
40 static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value);
41 static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
42                 uint32_t size, uint8_t *buffer);
43 static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
44                 uint32_t size, const uint8_t *buffer);
45
46 #define HW_THREAD_NAME_STR_SIZE (32)
47
48 extern int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
49
50 static inline threadid_t threadid_from_target(const struct target *target)
51 {
52         return target->coreid + 1;
53 }
54
55 const struct rtos_type hwthread_rtos = {
56         .name = "hwthread",
57         .detect_rtos = hwthread_detect_rtos,
58         .create = hwthread_create,
59         .update_threads = hwthread_update_threads,
60         .get_thread_reg_list = hwthread_get_thread_reg_list,
61         .get_thread_reg = hwthread_get_thread_reg,
62         .get_symbol_list_to_lookup = hwthread_get_symbol_list_to_lookup,
63         .smp_init = hwthread_smp_init,
64         .set_reg = hwthread_set_reg,
65         .read_buffer = hwthread_read_buffer,
66         .write_buffer = hwthread_write_buffer,
67 };
68
69 struct hwthread_params {
70         int dummy_param;
71 };
72
73 static int hwthread_fill_thread(struct rtos *rtos, struct target *curr, int thread_num)
74 {
75         char tmp_str[HW_THREAD_NAME_STR_SIZE];
76         threadid_t tid = threadid_from_target(curr);
77
78         memset(tmp_str, 0, HW_THREAD_NAME_STR_SIZE);
79
80         /* thread-id is the core-id of this core inside the SMP group plus 1 */
81         rtos->thread_details[thread_num].threadid = tid;
82         /* create the thread name */
83         rtos->thread_details[thread_num].exists = true;
84         rtos->thread_details[thread_num].thread_name_str = strdup(target_name(curr));
85         snprintf(tmp_str, HW_THREAD_NAME_STR_SIZE-1, "state: %s", debug_reason_name(curr));
86         rtos->thread_details[thread_num].extra_info_str = strdup(tmp_str);
87
88         return ERROR_OK;
89 }
90
91 static int hwthread_update_threads(struct rtos *rtos)
92 {
93         int threads_found = 0;
94         int thread_list_size = 0;
95         struct target_list *head;
96         struct target *target;
97         int64_t current_thread = 0;
98         enum target_debug_reason current_reason = DBG_REASON_UNDEFINED;
99
100         if (!rtos)
101                 return -1;
102
103         target = rtos->target;
104
105         /* wipe out previous thread details if any */
106         rtos_free_threadlist(rtos);
107
108         /* determine the number of "threads" */
109         if (target->smp) {
110                 for (head = target->head; head != NULL; head = head->next) {
111                         struct target *curr = head->target;
112
113                         if (!target_was_examined(curr))
114                                 continue;
115
116                         ++thread_list_size;
117                 }
118         } else
119                 thread_list_size = 1;
120
121         /* create space for new thread details */
122         rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
123
124         if (target->smp) {
125                 /* loop over all threads */
126                 for (head = target->head; head != NULL; head = head->next) {
127                         struct target *curr = head->target;
128
129                         if (!target_was_examined(curr))
130                                 continue;
131
132                         threadid_t tid = threadid_from_target(curr);
133
134                         hwthread_fill_thread(rtos, curr, threads_found);
135
136                         /* find an interesting thread to set as current */
137                         switch (current_reason) {
138                         case DBG_REASON_UNDEFINED:
139                                 current_reason = curr->debug_reason;
140                                 current_thread = tid;
141                                 break;
142                         case DBG_REASON_SINGLESTEP:
143                                 /* single-step can only be overridden by itself */
144                                 if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
145                                         if (tid == rtos->current_threadid)
146                                                 current_thread = tid;
147                                 }
148                                 break;
149                         case DBG_REASON_BREAKPOINT:
150                                 /* single-step overrides breakpoint */
151                                 if (curr->debug_reason == DBG_REASON_SINGLESTEP) {
152                                         current_reason = curr->debug_reason;
153                                         current_thread = tid;
154                                 } else
155                                 /* multiple breakpoints, prefer gdbs' threadid */
156                                 if (curr->debug_reason == DBG_REASON_BREAKPOINT) {
157                                         if (tid == rtos->current_threadid)
158                                                 current_thread = tid;
159                                 }
160                                 break;
161                         case DBG_REASON_WATCHPOINT:
162                                 /* breakpoint and single-step override watchpoint */
163                                 if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
164                                                 curr->debug_reason == DBG_REASON_BREAKPOINT) {
165                                         current_reason = curr->debug_reason;
166                                         current_thread = tid;
167                                 }
168                                 break;
169                         case DBG_REASON_DBGRQ:
170                                 /* all other reasons override debug-request */
171                                 if (curr->debug_reason == DBG_REASON_SINGLESTEP ||
172                                                 curr->debug_reason == DBG_REASON_WATCHPOINT ||
173                                                 curr->debug_reason == DBG_REASON_BREAKPOINT) {
174                                         current_reason = curr->debug_reason;
175                                         current_thread = tid;
176                                 } else
177                                 if (curr->debug_reason == DBG_REASON_DBGRQ) {
178                                         if (tid == rtos->current_threadid)
179                                                 current_thread = tid;
180                                 }
181
182                                 break;
183
184                         default:
185                                 break;
186                         }
187
188                         threads_found++;
189                 }
190         } else {
191                 hwthread_fill_thread(rtos, target, threads_found);
192                 current_thread = threadid_from_target(target);
193                 threads_found++;
194         }
195
196         rtos->thread_count = threads_found;
197
198         /* we found an interesting thread, set it as current */
199         if (current_thread != 0)
200                 rtos->current_thread = current_thread;
201         else if (rtos->current_threadid != 0)
202                 rtos->current_thread = rtos->current_threadid;
203         else
204                 rtos->current_thread = threadid_from_target(target);
205
206         LOG_DEBUG("%s current_thread=%i", __func__, (int)rtos->current_thread);
207         return 0;
208 }
209
210 static int hwthread_smp_init(struct target *target)
211 {
212         return hwthread_update_threads(target->rtos);
213 }
214
215 static struct target *hwthread_find_thread(struct target *target, int64_t thread_id)
216 {
217         /* Find the thread with that thread_id */
218         if (!target)
219                 return NULL;
220         if (target->smp) {
221                 for (struct target_list *head = target->head; head != NULL; head = head->next) {
222                         if (thread_id == threadid_from_target(head->target))
223                                 return head->target;
224                 }
225         } else if (thread_id == threadid_from_target(target)) {
226                 return target;
227         }
228         return NULL;
229 }
230
231 static int hwthread_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
232                 struct rtos_reg **rtos_reg_list, int *rtos_reg_list_size)
233 {
234         if (!rtos)
235                 return ERROR_FAIL;
236
237         struct target *target = rtos->target;
238
239         struct target *curr = hwthread_find_thread(target, thread_id);
240         if (!curr)
241                 return ERROR_FAIL;
242
243         if (!target_was_examined(curr))
244                 return ERROR_FAIL;
245
246         int reg_list_size;
247         struct reg **reg_list;
248         int retval = target_get_gdb_reg_list(curr, &reg_list, &reg_list_size,
249                         REG_CLASS_GENERAL);
250         if (retval != ERROR_OK)
251                 return retval;
252
253         int j = 0;
254         for (int i = 0; i < reg_list_size; i++) {
255                 if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden)
256                         continue;
257                 j++;
258         }
259         *rtos_reg_list_size = j;
260         *rtos_reg_list = calloc(*rtos_reg_list_size, sizeof(struct rtos_reg));
261         if (*rtos_reg_list == NULL) {
262                 free(reg_list);
263                 return ERROR_FAIL;
264         }
265
266         j = 0;
267         for (int i = 0; i < reg_list_size; i++) {
268                 if (reg_list[i] == NULL || reg_list[i]->exist == false || reg_list[i]->hidden)
269                         continue;
270                 (*rtos_reg_list)[j].number = (*reg_list)[i].number;
271                 (*rtos_reg_list)[j].size = (*reg_list)[i].size;
272                 memcpy((*rtos_reg_list)[j].value, (*reg_list)[i].value,
273                                 ((*reg_list)[i].size + 7) / 8);
274                 j++;
275         }
276         free(reg_list);
277
278         return ERROR_OK;
279 }
280
281 static int hwthread_get_thread_reg(struct rtos *rtos, int64_t thread_id,
282                 uint32_t reg_num, struct rtos_reg *rtos_reg)
283 {
284         if (!rtos)
285                 return ERROR_FAIL;
286
287         struct target *target = rtos->target;
288
289         struct target *curr = hwthread_find_thread(target, thread_id);
290         if (!curr) {
291                 LOG_ERROR("Couldn't find RTOS thread for id %" PRId64 ".", thread_id);
292                 return ERROR_FAIL;
293         }
294
295         if (!target_was_examined(curr)) {
296                 LOG_ERROR("Target %d hasn't been examined yet.", curr->coreid);
297                 return ERROR_FAIL;
298         }
299
300         struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
301         if (!reg) {
302                 LOG_ERROR("Couldn't find register %" PRIu32 " in thread %" PRId64 ".", reg_num,
303                                 thread_id);
304                 return ERROR_FAIL;
305         }
306
307         if (reg->type->get(reg) != ERROR_OK)
308                 return ERROR_FAIL;
309
310         rtos_reg->number = reg->number;
311         rtos_reg->size = reg->size;
312         unsigned bytes = (reg->size + 7) / 8;
313         assert(bytes <= sizeof(rtos_reg->value));
314         memcpy(rtos_reg->value, reg->value, bytes);
315
316         return ERROR_OK;
317 }
318
319 static int hwthread_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value)
320 {
321         if (!rtos)
322                 return ERROR_FAIL;
323
324         struct target *target = rtos->target;
325
326         struct target *curr = hwthread_find_thread(target, rtos->current_thread);
327         if (!curr)
328                 return ERROR_FAIL;
329
330         struct reg *reg = register_get_by_number(curr->reg_cache, reg_num, true);
331         if (!reg)
332                 return ERROR_FAIL;
333
334         return reg->type->set(reg, reg_value);
335 }
336
337 static int hwthread_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
338 {
339         /* return an empty list, we don't have any symbols to look up */
340         *symbol_list = calloc(1, sizeof(struct symbol_table_elem));
341         (*symbol_list)[0].symbol_name = NULL;
342         return 0;
343 }
344
345 static int hwthread_target_for_threadid(struct connection *connection, int64_t thread_id, struct target **p_target)
346 {
347         struct target *target = get_target_from_connection(connection);
348
349         struct target *curr = hwthread_find_thread(target, thread_id);
350         if (!curr)
351                 return ERROR_FAIL;
352
353         *p_target = curr;
354
355         return ERROR_OK;
356 }
357
358 static bool hwthread_detect_rtos(struct target *target)
359 {
360         /* always return 0, avoid auto-detection */
361         return false;
362 }
363
364 static int hwthread_thread_packet(struct connection *connection, const char *packet, int packet_size)
365 {
366         struct target *target = get_target_from_connection(connection);
367
368         struct target *curr = NULL;
369         int64_t current_threadid;
370
371         if (packet[0] == 'H' && packet[1] == 'g') {
372                 sscanf(packet, "Hg%16" SCNx64, &current_threadid);
373
374                 if (current_threadid > 0) {
375                         if (hwthread_target_for_threadid(connection, current_threadid, &curr) != ERROR_OK) {
376                                 LOG_ERROR("hwthread: cannot find thread id %"PRId64, current_threadid);
377                                 gdb_put_packet(connection, "E01", 3);
378                                 return ERROR_FAIL;
379                         }
380                         target->rtos->current_thread = current_threadid;
381                 } else
382                 if (current_threadid == 0 || current_threadid == -1)
383                         target->rtos->current_thread = threadid_from_target(target);
384
385                 target->rtos->current_threadid = current_threadid;
386
387                 gdb_put_packet(connection, "OK", 2);
388                 return ERROR_OK;
389         }
390
391         return rtos_thread_packet(connection, packet, packet_size);
392 }
393
394 static int hwthread_create(struct target *target)
395 {
396         LOG_INFO("Hardware thread awareness created");
397
398         target->rtos->rtos_specific_params = NULL;
399         target->rtos->current_thread = 0;
400         target->rtos->thread_details = NULL;
401         target->rtos->gdb_target_for_threadid = hwthread_target_for_threadid;
402         target->rtos->gdb_thread_packet = hwthread_thread_packet;
403         return 0;
404 }
405
406 static int hwthread_read_buffer(struct rtos *rtos, target_addr_t address,
407                 uint32_t size, uint8_t *buffer)
408 {
409         if (!rtos)
410                 return ERROR_FAIL;
411
412         struct target *target = rtos->target;
413
414         struct target *curr = hwthread_find_thread(target, rtos->current_thread);
415         if (!curr)
416                 return ERROR_FAIL;
417
418         return target_read_buffer(curr, address, size, buffer);
419 }
420
421 static int hwthread_write_buffer(struct rtos *rtos, target_addr_t address,
422                 uint32_t size, const uint8_t *buffer)
423 {
424         if (!rtos)
425                 return ERROR_FAIL;
426
427         struct target *target = rtos->target;
428
429         struct target *curr = hwthread_find_thread(target, rtos->current_thread);
430         if (!curr)
431                 return ERROR_FAIL;
432
433         return target_write_buffer(curr, address, size, buffer);
434 }