d147c1cf0e97f4e6b8bdcac5ef764a14e842a38b
[openocd.git] / src / rtos / linux.c
1 /***************************************************************************
2 * Copyright (C) 2011 by STEricsson *
3 * Heythem Bouhaja heythem.bouhaja@stericsson.com : creation *
4 * Michel JAOUEN michel.jaouen@stericsson.com : adaptation to rtos *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 ***************************************************************************/
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <helper/time_support.h>
25 #include <jtag/jtag.h>
26 #include "target/target.h"
27 #include "target/target_type.h"
28 #include "helper/log.h"
29 #include "helper/types.h"
30 #include "rtos.h"
31 #include "rtos_standard_stackings.h"
32 #include <target/register.h>
33 #include <target/smp.h>
34 #include "server/gdb_server.h"
35
36 #define LINUX_USER_KERNEL_BORDER 0xc0000000
37 #include "linux_header.h"
38 #define PHYS
39 #define MAX_THREADS 200
40 /* specific task */
41 struct linux_os {
42 const char *name;
43 uint32_t init_task_addr;
44 int thread_count;
45 int threadid_count;
46 int preupdtate_threadid_count;
47 int nr_cpus;
48 int threads_lookup;
49 int threads_needs_update;
50 struct current_thread *current_threads;
51 struct threads *thread_list;
52 /* virt2phys parameter */
53 uint32_t phys_mask;
54 uint32_t phys_base;
55 };
56
57 struct current_thread {
58 int64_t threadid;
59 int32_t core_id;
60 #ifdef PID_CHECK
61 uint32_t pid;
62 #endif
63 uint32_t TS;
64 struct current_thread *next;
65 };
66
67 struct threads {
68 char name[17];
69 uint32_t base_addr; /* address to read magic */
70 uint32_t state; /* magic value : filled only at creation */
71 uint32_t pid; /* linux pid : id for identifying a thread */
72 uint32_t oncpu; /* content cpu number in current thread */
73 uint32_t asid; /* filled only at creation */
74 int64_t threadid;
75 int status; /* dead = 1 alive = 2 current = 3 alive and current */
76 /* value that should not change during the live of a thread ? */
77 uint32_t thread_info_addr; /* contain latest thread_info_addr computed */
78 /* retrieve from thread_info */
79 struct cpu_context *context;
80 struct threads *next;
81 };
82
83 struct cpu_context {
84 uint32_t R4;
85 uint32_t R5;
86 uint32_t R6;
87 uint32_t R7;
88 uint32_t R8;
89 uint32_t R9;
90 uint32_t IP;
91 uint32_t FP;
92 uint32_t SP;
93 uint32_t PC;
94 uint32_t preempt_count;
95 };
96 static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
97 uint32_t *info_addr);
98 static int insert_into_threadlist(struct target *target, struct threads *t);
99
100 static int linux_os_create(struct target *target);
101
102 static int linux_os_dummy_update(struct rtos *rtos)
103 {
104 /* update is done only when thread request come
105 * too many thread to do it on each stop */
106 return 0;
107 }
108
109 static int linux_compute_virt2phys(struct target *target, target_addr_t address)
110 {
111 struct linux_os *linux_os = (struct linux_os *)
112 target->rtos->rtos_specific_params;
113 target_addr_t pa = 0;
114 int retval = target->type->virt2phys(target, address, &pa);
115 if (retval != ERROR_OK) {
116 LOG_ERROR("Cannot compute linux virt2phys translation");
117 /* fixes default address */
118 linux_os->phys_base = 0;
119 return ERROR_FAIL;
120 }
121
122 linux_os->init_task_addr = address;
123 address = address & linux_os->phys_mask;
124 linux_os->phys_base = pa - address;
125 return ERROR_OK;
126 }
127
128 static int linux_read_memory(struct target *target,
129 uint32_t address, uint32_t size, uint32_t count,
130 uint8_t *buffer)
131 {
132 #ifdef PHYS
133 struct linux_os *linux_os = (struct linux_os *)
134 target->rtos->rtos_specific_params;
135 uint32_t pa = (address & linux_os->phys_mask) + linux_os->phys_base;
136 #endif
137 if (address < 0xc000000) {
138 LOG_ERROR("linux awareness : address in user space");
139 return ERROR_FAIL;
140 }
141 #ifdef PHYS
142 target_read_phys_memory(target, pa, size, count, buffer);
143 #endif
144 target_read_memory(target, address, size, count, buffer);
145 return ERROR_OK;
146 }
147
148 static int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer)
149 {
150
151 if ((addr & 0xfffffffc) != addr)
152 LOG_INFO("unaligned address %" PRIx32 "!!", addr);
153
154 int retval = linux_read_memory(target, addr, 4, 1, buffer);
155 return retval;
156
157 }
158
159 static uint32_t get_buffer(struct target *target, const uint8_t *buffer)
160 {
161 uint32_t value = 0;
162 const uint8_t *value_ptr = buffer;
163 value = target_buffer_get_u32(target, value_ptr);
164 return value;
165 }
166
167 static int linux_os_thread_reg_list(struct rtos *rtos,
168 int64_t thread_id, struct rtos_reg **reg_list, int *num_regs)
169 {
170 struct target *target = rtos->target;
171 struct linux_os *linux_os = (struct linux_os *)
172 target->rtos->rtos_specific_params;
173 struct current_thread *tmp = linux_os->current_threads;
174 struct current_thread *next;
175 int found = 0;
176 int retval;
177 /* check if a current thread is requested */
178 next = tmp;
179
180 do {
181 if (next->threadid == thread_id)
182 found = 1;
183 else
184 next = next->next;
185 } while ((found == 0) && (next != tmp) && (next));
186
187 if (found == 0) {
188 LOG_ERROR("could not find thread: %" PRIx64, thread_id);
189 return ERROR_FAIL;
190 }
191
192 /* search target to perform the access */
193 struct reg **gdb_reg_list;
194 struct target_list *head;
195 found = 0;
196 foreach_smp_target(head, target->smp_targets) {
197 if (head->target->coreid == next->core_id) {
198 target = head->target;
199 found = 1;
200 break;
201 }
202 }
203
204 if (found == 0) {
205 LOG_ERROR
206 (
207 "current thread %" PRIx64 ": no target to perform access of core id %" PRIx32,
208 thread_id,
209 next->core_id);
210 return ERROR_FAIL;
211 }
212
213 /*LOG_INFO("thread %lx current on core %x",thread_id, target->coreid);*/
214 retval = target_get_gdb_reg_list(target, &gdb_reg_list, num_regs, REG_CLASS_GENERAL);
215 if (retval != ERROR_OK)
216 return retval;
217
218 *reg_list = calloc(*num_regs, sizeof(struct rtos_reg));
219
220 for (int i = 0; i < *num_regs; ++i) {
221 if (!gdb_reg_list[i]->valid)
222 gdb_reg_list[i]->type->get(gdb_reg_list[i]);
223
224 (*reg_list)[i].number = gdb_reg_list[i]->number;
225 (*reg_list)[i].size = gdb_reg_list[i]->size;
226
227 buf_cpy(gdb_reg_list[i]->value, (*reg_list)[i].value, (*reg_list)[i].size);
228 }
229
230 return ERROR_OK;
231 }
232
233 static bool linux_os_detect(struct target *target)
234 {
235 LOG_INFO("should no be called");
236 return false;
237 }
238
239 static int linux_os_smp_init(struct target *target);
240 static int linux_os_clean(struct target *target);
241 #define INIT_TASK 0
242 static const char * const linux_symbol_list[] = {
243 "init_task",
244 NULL
245 };
246
247 static int linux_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
248 {
249 unsigned int i;
250 *symbol_list = (struct symbol_table_elem *)
251 calloc(ARRAY_SIZE(linux_symbol_list), sizeof(struct symbol_table_elem));
252
253 for (i = 0; i < ARRAY_SIZE(linux_symbol_list); i++)
254 (*symbol_list)[i].symbol_name = linux_symbol_list[i];
255
256 return 0;
257 }
258
259 static char *linux_ps_command(struct target *target);
260
261 const struct rtos_type linux_rtos = {
262 .name = "linux",
263 .detect_rtos = linux_os_detect,
264 .create = linux_os_create,
265 .smp_init = linux_os_smp_init,
266 .update_threads = linux_os_dummy_update,
267 .get_thread_reg_list = linux_os_thread_reg_list,
268 .get_symbol_list_to_lookup = linux_get_symbol_list_to_lookup,
269 .clean = linux_os_clean,
270 .ps_command = linux_ps_command,
271 };
272
273 static int linux_thread_packet(struct connection *connection, char const *packet,
274 int packet_size);
275 static void linux_identify_current_threads(struct target *target);
276
277 #ifdef PID_CHECK
278 int fill_task_pid(struct target *target, struct threads *t)
279 {
280 uint32_t pid_addr = t->base_addr + PID;
281 uint8_t buffer[4];
282 int retval = fill_buffer(target, pid_addr, buffer);
283
284 if (retval == ERROR_OK) {
285 uint32_t val = get_buffer(target, buffer);
286 t->pid = val;
287 } else
288 LOG_ERROR("fill_task_pid: unable to read memory");
289
290 return retval;
291 }
292 #endif
293
294 static int fill_task(struct target *target, struct threads *t)
295 {
296 int retval;
297 uint32_t pid_addr = t->base_addr + PID;
298 uint32_t mem_addr = t->base_addr + MEM;
299 uint32_t on_cpu = t->base_addr + ONCPU;
300 uint8_t *buffer = calloc(1, 4);
301 retval = fill_buffer(target, t->base_addr, buffer);
302
303 if (retval == ERROR_OK) {
304 uint32_t val = get_buffer(target, buffer);
305 t->state = val;
306 } else
307 LOG_ERROR("fill_task: unable to read memory");
308
309 retval = fill_buffer(target, pid_addr, buffer);
310
311 if (retval == ERROR_OK) {
312 uint32_t val = get_buffer(target, buffer);
313 t->pid = val;
314 } else
315 LOG_ERROR("fill task: unable to read memory");
316
317 retval = fill_buffer(target, on_cpu, buffer);
318
319 if (retval == ERROR_OK) {
320 uint32_t val = get_buffer(target, buffer);
321 t->oncpu = val;
322 } else
323 LOG_ERROR("fill task: unable to read memory");
324
325 retval = fill_buffer(target, mem_addr, buffer);
326
327 if (retval == ERROR_OK) {
328 uint32_t val = get_buffer(target, buffer);
329
330 if (val != 0) {
331 uint32_t asid_addr = val + MM_CTX;
332 retval = fill_buffer(target, asid_addr, buffer);
333
334 if (retval == ERROR_OK) {
335 val = get_buffer(target, buffer);
336 t->asid = val;
337 } else
338 LOG_ERROR
339 ("fill task: unable to read memory -- ASID");
340 } else
341 t->asid = 0;
342 } else
343 LOG_ERROR("fill task: unable to read memory");
344
345 free(buffer);
346
347 return retval;
348 }
349
350 static int get_name(struct target *target, struct threads *t)
351 {
352 int retval;
353 uint32_t full_name[4];
354 uint32_t comm = t->base_addr + COMM;
355 int i;
356
357 for (i = 0; i < 17; i++)
358 t->name[i] = 0;
359
360 retval = linux_read_memory(target, comm, 4, 4, (uint8_t *) full_name);
361
362 if (retval != ERROR_OK) {
363 LOG_ERROR("get_name: unable to read memory\n");
364 return ERROR_FAIL;
365 }
366
367 uint32_t raw_name = target_buffer_get_u32(target,
368 (const uint8_t *)
369 &full_name[0]);
370 t->name[3] = raw_name >> 24;
371 t->name[2] = raw_name >> 16;
372 t->name[1] = raw_name >> 8;
373 t->name[0] = raw_name;
374 raw_name =
375 target_buffer_get_u32(target, (const uint8_t *)&full_name[1]);
376 t->name[7] = raw_name >> 24;
377 t->name[6] = raw_name >> 16;
378 t->name[5] = raw_name >> 8;
379 t->name[4] = raw_name;
380 raw_name =
381 target_buffer_get_u32(target, (const uint8_t *)&full_name[2]);
382 t->name[11] = raw_name >> 24;
383 t->name[10] = raw_name >> 16;
384 t->name[9] = raw_name >> 8;
385 t->name[8] = raw_name;
386 raw_name =
387 target_buffer_get_u32(target, (const uint8_t *)&full_name[3]);
388 t->name[15] = raw_name >> 24;
389 t->name[14] = raw_name >> 16;
390 t->name[13] = raw_name >> 8;
391 t->name[12] = raw_name;
392 return ERROR_OK;
393
394 }
395
396 static int get_current(struct target *target, int create)
397 {
398 struct target_list *head;
399 uint8_t *buf;
400 uint32_t val;
401 uint32_t ti_addr;
402 uint8_t *buffer = calloc(1, 4);
403 struct linux_os *linux_os = (struct linux_os *)
404 target->rtos->rtos_specific_params;
405 struct current_thread *ctt = linux_os->current_threads;
406
407 /* invalid current threads content */
408 while (ctt) {
409 ctt->threadid = -1;
410 ctt->TS = 0xdeadbeef;
411 ctt = ctt->next;
412 }
413
414 foreach_smp_target(head, target->smp_targets) {
415 struct reg **reg_list;
416 int reg_list_size;
417 int retval;
418
419 if (target_get_gdb_reg_list(head->target, &reg_list,
420 &reg_list_size, REG_CLASS_GENERAL) != ERROR_OK) {
421 free(buffer);
422 return ERROR_TARGET_FAILURE;
423 }
424
425 if (!reg_list[13]->valid)
426 reg_list[13]->type->get(reg_list[13]);
427
428 buf = reg_list[13]->value;
429 val = get_buffer(target, buf);
430 ti_addr = (val & 0xffffe000);
431 uint32_t ts_addr = ti_addr + 0xc;
432 retval = fill_buffer(target, ts_addr, buffer);
433
434 if (retval == ERROR_OK) {
435 uint32_t TS = get_buffer(target, buffer);
436 uint32_t cpu, on_cpu = TS + ONCPU;
437 retval = fill_buffer(target, on_cpu, buffer);
438
439 if (retval == ERROR_OK) {
440 /*uint32_t cpu = get_buffer(target, buffer);*/
441 struct current_thread *ct =
442 linux_os->current_threads;
443 cpu = head->target->coreid;
444
445 while ((ct) && (ct->core_id != (int32_t) cpu))
446 ct = ct->next;
447
448 if ((ct) && (ct->TS == 0xdeadbeef))
449 ct->TS = TS;
450 else
451 LOG_ERROR
452 ("error in linux current thread update");
453
454 if (create && ct) {
455 struct threads *t;
456 t = calloc(1, sizeof(struct threads));
457 t->base_addr = ct->TS;
458 fill_task(target, t);
459 get_name(target, t);
460 t->oncpu = cpu;
461 insert_into_threadlist(target, t);
462 t->status = 3;
463 t->thread_info_addr = 0xdeadbeef;
464 ct->threadid = t->threadid;
465 linux_os->thread_count++;
466 #ifdef PID_CHECK
467 ct->pid = t->pid;
468 #endif
469 /*LOG_INFO("Creation of current thread %s",t->name);*/
470 }
471 }
472 }
473
474 free(reg_list);
475 }
476
477 free(buffer);
478
479 return ERROR_OK;
480 }
481
482 static struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
483 uint32_t *thread_info_addr_old)
484 {
485 struct cpu_context *context = calloc(1, sizeof(struct cpu_context));
486 uint32_t preempt_count_addr = 0;
487 uint32_t registers[10];
488 uint8_t *buffer = calloc(1, 4);
489 uint32_t stack = base_addr + QAT;
490 uint32_t thread_info_addr = 0;
491 uint32_t thread_info_addr_update = 0;
492 int retval = ERROR_FAIL;
493 context->R4 = 0xdeadbeef;
494 context->R5 = 0xdeadbeef;
495 context->R6 = 0xdeadbeef;
496 context->R7 = 0xdeadbeef;
497 context->R8 = 0xdeadbeef;
498 context->R9 = 0xdeadbeef;
499 context->IP = 0xdeadbeef;
500 context->FP = 0xdeadbeef;
501 context->SP = 0xdeadbeef;
502 context->PC = 0xdeadbeef;
503 retry:
504
505 if (*thread_info_addr_old == 0xdeadbeef) {
506 retval = fill_buffer(target, stack, buffer);
507
508 if (retval == ERROR_OK)
509 thread_info_addr = get_buffer(target, buffer);
510 else
511 LOG_ERROR("cpu_context: unable to read memory");
512
513 thread_info_addr_update = thread_info_addr;
514 } else
515 thread_info_addr = *thread_info_addr_old;
516
517 preempt_count_addr = thread_info_addr + PREEMPT;
518 retval = fill_buffer(target, preempt_count_addr, buffer);
519
520 if (retval == ERROR_OK)
521 context->preempt_count = get_buffer(target, buffer);
522 else {
523 if (*thread_info_addr_old != 0xdeadbeef) {
524 LOG_ERROR
525 ("cpu_context: cannot read at thread_info_addr");
526
527 if (*thread_info_addr_old < LINUX_USER_KERNEL_BORDER)
528 LOG_INFO
529 ("cpu_context : thread_info_addr in userspace!!!");
530
531 *thread_info_addr_old = 0xdeadbeef;
532 goto retry;
533 }
534
535 LOG_ERROR("cpu_context: unable to read memory");
536 }
537
538 thread_info_addr += CPU_CONT;
539
540 retval = linux_read_memory(target, thread_info_addr, 4, 10,
541 (uint8_t *) registers);
542
543 if (retval != ERROR_OK) {
544 free(buffer);
545 LOG_ERROR("cpu_context: unable to read memory\n");
546 return context;
547 }
548
549 context->R4 =
550 target_buffer_get_u32(target, (const uint8_t *)&registers[0]);
551 context->R5 =
552 target_buffer_get_u32(target, (const uint8_t *)&registers[1]);
553 context->R6 =
554 target_buffer_get_u32(target, (const uint8_t *)&registers[2]);
555 context->R7 =
556 target_buffer_get_u32(target, (const uint8_t *)&registers[3]);
557 context->R8 =
558 target_buffer_get_u32(target, (const uint8_t *)&registers[4]);
559 context->R9 =
560 target_buffer_get_u32(target, (const uint8_t *)&registers[5]);
561 context->IP =
562 target_buffer_get_u32(target, (const uint8_t *)&registers[6]);
563 context->FP =
564 target_buffer_get_u32(target, (const uint8_t *)&registers[7]);
565 context->SP =
566 target_buffer_get_u32(target, (const uint8_t *)&registers[8]);
567 context->PC =
568 target_buffer_get_u32(target, (const uint8_t *)&registers[9]);
569
570 if (*thread_info_addr_old == 0xdeadbeef)
571 *thread_info_addr_old = thread_info_addr_update;
572
573 free(buffer);
574
575 return context;
576 }
577
578 static uint32_t next_task(struct target *target, struct threads *t)
579 {
580 uint8_t *buffer = calloc(1, 4);
581 uint32_t next_addr = t->base_addr + NEXT;
582 int retval = fill_buffer(target, next_addr, buffer);
583
584 if (retval == ERROR_OK) {
585 uint32_t val = get_buffer(target, buffer);
586 val = val - NEXT;
587 free(buffer);
588 return val;
589 } else
590 LOG_ERROR("next task: unable to read memory");
591
592 free(buffer);
593
594 return 0;
595 }
596
597 static struct current_thread *add_current_thread(struct current_thread *currents,
598 struct current_thread *ct)
599 {
600 ct->next = NULL;
601
602 if (!currents) {
603 currents = ct;
604 return currents;
605 } else {
606 struct current_thread *temp = currents;
607
608 while (temp->next)
609 temp = temp->next;
610
611 temp->next = ct;
612 return currents;
613 }
614 }
615
616 static struct threads *liste_del_task(struct threads *task_list, struct threads **t,
617 struct threads *prev)
618 {
619 LOG_INFO("del task %" PRId64, (*t)->threadid);
620 if (prev)
621 prev->next = (*t)->next;
622 else
623 task_list = (*t)->next;
624
625 /* free content of threads */
626 free((*t)->context);
627
628 free(*t);
629 *t = prev ? prev : task_list;
630 return task_list;
631 }
632
633 static struct threads *liste_add_task(struct threads *task_list, struct threads *t,
634 struct threads **last)
635 {
636 t->next = NULL;
637
638 if (!*last)
639 if (!task_list) {
640 task_list = t;
641 return task_list;
642 } else {
643 struct threads *temp = task_list;
644
645 while (temp->next)
646 temp = temp->next;
647
648 temp->next = t;
649 *last = t;
650 return task_list;
651 } else {
652 (*last)->next = t;
653 *last = t;
654 return task_list;
655 }
656 }
657
658 #ifdef PID_CHECK
659 static int current_pid(struct linux_os *linux_os, uint32_t pid)
660 #else
661 static int current_base_addr(struct linux_os *linux_os, uint32_t base_addr)
662 #endif
663 {
664 struct current_thread *ct = linux_os->current_threads;
665 #ifdef PID_CHECK
666
667 while ((ct) && (ct->pid != pid))
668 #else
669 while ((ct) && (ct->TS != base_addr))
670 #endif
671 ct = ct->next;
672 #ifdef PID_CHECK
673 if ((ct) && (ct->pid == pid))
674 #else
675 if ((ct) && (ct->TS == base_addr))
676 #endif
677 return 1;
678
679 return 0;
680 }
681
682 static int linux_get_tasks(struct target *target, int context)
683 {
684 int loop = 0;
685 int retval = 0;
686 struct linux_os *linux_os = (struct linux_os *)
687 target->rtos->rtos_specific_params;
688 linux_os->thread_list = NULL;
689 linux_os->thread_count = 0;
690
691 if (linux_os->init_task_addr == 0xdeadbeef) {
692 LOG_INFO("no init symbol\n");
693 return ERROR_FAIL;
694 }
695
696 int64_t start = timeval_ms();
697
698 struct threads *t = calloc(1, sizeof(struct threads));
699 struct threads *last = NULL;
700 t->base_addr = linux_os->init_task_addr;
701 /* retrieve the thread id , currently running in the different smp core */
702 get_current(target, 1);
703
704 while (((t->base_addr != linux_os->init_task_addr) &&
705 (t->base_addr != 0)) || (loop == 0)) {
706 loop++;
707 fill_task(target, t);
708 retval = get_name(target, t);
709
710 if (loop > MAX_THREADS) {
711 free(t);
712 LOG_INFO("more than %d threads !!", MAX_THREADS);
713 return ERROR_FAIL;
714 }
715
716 if (retval != ERROR_OK) {
717 free(t);
718 return ERROR_FAIL;
719 }
720
721 /* check that this thread is not one the current threads already
722 * created */
723 uint32_t base_addr;
724 #ifdef PID_CHECK
725
726 if (!current_pid(linux_os, t->pid)) {
727 #else
728 if (!current_base_addr(linux_os, t->base_addr)) {
729 #endif
730 t->threadid = linux_os->threadid_count;
731 t->status = 1;
732 linux_os->threadid_count++;
733
734 linux_os->thread_list =
735 liste_add_task(linux_os->thread_list, t, &last);
736 /* no interest to fill the context if it is a current thread. */
737 linux_os->thread_count++;
738 t->thread_info_addr = 0xdeadbeef;
739
740 if (context)
741 t->context =
742 cpu_context_read(target, t->base_addr,
743 &t->thread_info_addr);
744 base_addr = next_task(target, t);
745 } else {
746 /*LOG_INFO("thread %s is a current thread already created",t->name); */
747 base_addr = next_task(target, t);
748 free(t);
749 }
750
751 t = calloc(1, sizeof(struct threads));
752 t->base_addr = base_addr;
753 }
754
755 linux_os->threads_lookup = 1;
756 linux_os->threads_needs_update = 0;
757 linux_os->preupdtate_threadid_count = linux_os->threadid_count - 1;
758 /* check that all current threads have been identified */
759
760 LOG_INFO("complete time %" PRId64 ", thread mean %" PRId64 "\n",
761 (timeval_ms() - start),
762 (timeval_ms() - start) / linux_os->threadid_count);
763
764 LOG_INFO("threadid count %d", linux_os->threadid_count);
765 free(t);
766
767 return ERROR_OK;
768 }
769
770 static int clean_threadlist(struct target *target)
771 {
772 struct linux_os *linux_os = (struct linux_os *)
773 target->rtos->rtos_specific_params;
774 struct threads *old, *temp = linux_os->thread_list;
775
776 while (temp) {
777 old = temp;
778
779 free(temp->context);
780
781 temp = temp->next;
782 free(old);
783 }
784
785 return ERROR_OK;
786 }
787
788 static int linux_os_clean(struct target *target)
789 {
790 struct linux_os *os_linux = (struct linux_os *)
791 target->rtos->rtos_specific_params;
792 clean_threadlist(target);
793 os_linux->init_task_addr = 0xdeadbeef;
794 os_linux->name = "linux";
795 os_linux->thread_list = NULL;
796 os_linux->thread_count = 0;
797 os_linux->nr_cpus = 0;
798 os_linux->threads_lookup = 0;
799 os_linux->threads_needs_update = 0;
800 os_linux->threadid_count = 1;
801 return ERROR_OK;
802 }
803
804 static int insert_into_threadlist(struct target *target, struct threads *t)
805 {
806 struct linux_os *linux_os = (struct linux_os *)
807 target->rtos->rtos_specific_params;
808 struct threads *temp = linux_os->thread_list;
809 t->threadid = linux_os->threadid_count;
810 linux_os->threadid_count++;
811 t->status = 1;
812 t->next = NULL;
813
814 if (!temp)
815 linux_os->thread_list = t;
816 else {
817 while (temp->next)
818 temp = temp->next;
819
820 t->next = NULL;
821 temp->next = t;
822 }
823
824 return ERROR_OK;
825 }
826
827 static void linux_identify_current_threads(struct target *target)
828 {
829 struct linux_os *linux_os = (struct linux_os *)
830 target->rtos->rtos_specific_params;
831 struct threads *thread_list = linux_os->thread_list;
832 struct current_thread *ct = linux_os->current_threads;
833 struct threads *t = NULL;
834
835 while ((ct)) {
836 if (ct->threadid == -1) {
837
838 /* un-identified thread */
839 int found = 0;
840 t = calloc(1, sizeof(struct threads));
841 t->base_addr = ct->TS;
842 #ifdef PID_CHECK
843
844 if (fill_task_pid(target, t) != ERROR_OK) {
845 error_handling:
846 free(t);
847 LOG_ERROR
848 ("linux identify_current_threads: unable to read pid");
849 return;
850 }
851 #endif
852
853 /* search in the list of threads if pid
854 already present */
855 while ((thread_list) && (found == 0)) {
856 #ifdef PID_CHECK
857 if (thread_list->pid == t->pid) {
858 #else
859 if (thread_list->base_addr == t->base_addr) {
860 #endif
861 free(t);
862 t = thread_list;
863 found = 1;
864 }
865 thread_list = thread_list->next;
866 }
867
868 if (!found) {
869 /* it is a new thread */
870 if (fill_task(target, t) != ERROR_OK)
871 goto error_handling;
872
873 get_name(target, t);
874 insert_into_threadlist(target, t);
875 t->thread_info_addr = 0xdeadbeef;
876 }
877
878 t->status = 3;
879 ct->threadid = t->threadid;
880 #ifdef PID_CHECK
881 ct->pid = t->pid;
882 #endif
883 linux_os->thread_count++;
884 #if 0
885 if (found == 0)
886 LOG_INFO("current thread core %x identified %s",
887 ct->core_id, t->name);
888 else
889 LOG_INFO("current thread core %x, reused %s",
890 ct->core_id, t->name);
891 #endif
892 }
893 #if 0
894 else {
895 struct threads tmp;
896 tmp.base_addr = ct->TS;
897 get_name(target, &tmp);
898 LOG_INFO("current thread core %x , already identified %s !!!",
899 ct->core_id, tmp.name);
900 }
901 #endif
902 ct = ct->next;
903 }
904
905 return;
906 #ifndef PID_CHECK
907 error_handling:
908 free(t);
909 LOG_ERROR("unable to read pid");
910 return;
911
912 #endif
913 }
914
915 static int linux_task_update(struct target *target, int context)
916 {
917 struct linux_os *linux_os = (struct linux_os *)
918 target->rtos->rtos_specific_params;
919 struct threads *thread_list = linux_os->thread_list;
920 int retval;
921 int loop = 0;
922 linux_os->thread_count = 0;
923
924 /*thread_list = thread_list->next; skip init_task*/
925 while (thread_list) {
926 thread_list->status = 0; /*setting all tasks to dead state*/
927
928 free(thread_list->context);
929 thread_list->context = NULL;
930
931 thread_list = thread_list->next;
932 }
933
934 int found = 0;
935
936 if (linux_os->init_task_addr == 0xdeadbeef) {
937 LOG_INFO("no init symbol\n");
938 return ERROR_FAIL;
939 }
940 int64_t start = timeval_ms();
941 struct threads *t = calloc(1, sizeof(struct threads));
942 uint32_t previous = 0xdeadbeef;
943 t->base_addr = linux_os->init_task_addr;
944 retval = get_current(target, 0);
945 /*check that all current threads have been identified */
946 linux_identify_current_threads(target);
947
948 while (((t->base_addr != linux_os->init_task_addr) &&
949 (t->base_addr != previous)) || (loop == 0)) {
950 /* for avoiding any permanent loop for any reason possibly due to
951 * target */
952 loop++;
953 previous = t->base_addr;
954 /* read only pid */
955 #ifdef PID_CHECK
956 retval = fill_task_pid(target, t);
957 #endif
958
959 if (retval != ERROR_OK) {
960 free(t);
961 return ERROR_FAIL;
962 }
963
964 thread_list = linux_os->thread_list;
965
966 while (thread_list) {
967 #ifdef PID_CHECK
968 if (t->pid == thread_list->pid) {
969 #else
970 if (t->base_addr == thread_list->base_addr) {
971 #endif
972 if (!thread_list->status) {
973 #ifdef PID_CHECK
974 if (t->base_addr != thread_list->base_addr)
975 LOG_INFO("thread base_addr has changed !!");
976 #endif
977 /* this is not a current thread */
978 thread_list->base_addr = t->base_addr;
979 thread_list->status = 1;
980
981 /* we don 't update this field any more */
982
983 /*thread_list->state = t->state;
984 thread_list->oncpu = t->oncpu;
985 thread_list->asid = t->asid;
986 */
987 if (context)
988 thread_list->context =
989 cpu_context_read(target,
990 thread_list->base_addr,
991 &thread_list->thread_info_addr);
992 } else {
993 /* it is a current thread no need to read context */
994 }
995
996 linux_os->thread_count++;
997 found = 1;
998 break;
999 } else {
1000 found = 0;
1001 thread_list = thread_list->next;
1002 }
1003 }
1004
1005 if (found == 0) {
1006 uint32_t base_addr;
1007 fill_task(target, t);
1008 get_name(target, t);
1009 retval = insert_into_threadlist(target, t);
1010 t->thread_info_addr = 0xdeadbeef;
1011
1012 if (context)
1013 t->context =
1014 cpu_context_read(target, t->base_addr,
1015 &t->thread_info_addr);
1016
1017 base_addr = next_task(target, t);
1018 t = calloc(1, sizeof(struct threads));
1019 t->base_addr = base_addr;
1020 linux_os->thread_count++;
1021 } else
1022 t->base_addr = next_task(target, t);
1023 }
1024
1025 LOG_INFO("update thread done %" PRId64 ", mean%" PRId64 "\n",
1026 (timeval_ms() - start), (timeval_ms() - start) / loop);
1027 free(t);
1028 linux_os->threads_needs_update = 0;
1029 return ERROR_OK;
1030 }
1031
1032 static int linux_gdb_thread_packet(struct target *target,
1033 struct connection *connection, char const *packet,
1034 int packet_size)
1035 {
1036 int retval;
1037 struct linux_os *linux_os =
1038 (struct linux_os *)target->rtos->rtos_specific_params;
1039
1040 if (linux_os->init_task_addr == 0xdeadbeef) {
1041 /* it has not been initialized */
1042 LOG_INFO("received thread request without init task address");
1043 gdb_put_packet(connection, "l", 1);
1044 return ERROR_OK;
1045 }
1046
1047 retval = linux_get_tasks(target, 1);
1048
1049 if (retval != ERROR_OK)
1050 return ERROR_TARGET_FAILURE;
1051
1052 char *out_str = calloc(MAX_THREADS * 17 + 10, 1);
1053 char *tmp_str = out_str;
1054 tmp_str += sprintf(tmp_str, "m");
1055 struct threads *temp = linux_os->thread_list;
1056
1057 while (temp) {
1058 tmp_str += sprintf(tmp_str, "%016" PRIx64, temp->threadid);
1059 temp = temp->next;
1060 if (temp)
1061 tmp_str += sprintf(tmp_str, ",");
1062 }
1063
1064 gdb_put_packet(connection, out_str, strlen(out_str));
1065 free(out_str);
1066 return ERROR_OK;
1067 }
1068
1069 static int linux_gdb_thread_update(struct target *target,
1070 struct connection *connection, char const *packet,
1071 int packet_size)
1072 {
1073 int found = 0;
1074 struct linux_os *linux_os = (struct linux_os *)
1075 target->rtos->rtos_specific_params;
1076 struct threads *temp = linux_os->thread_list;
1077
1078 while (temp) {
1079 if (temp->threadid == linux_os->preupdtate_threadid_count + 1) {
1080 /*LOG_INFO("FOUND");*/
1081 found = 1;
1082 break;
1083 } else
1084 temp = temp->next;
1085 }
1086
1087 if (found == 1) {
1088 /*LOG_INFO("INTO GDB THREAD UPDATE FOUNDING START TASK");*/
1089 char *out_strr = calloc(MAX_THREADS * 17 + 10, 1);
1090 char *tmp_strr = out_strr;
1091 tmp_strr += sprintf(tmp_strr, "m");
1092 /*LOG_INFO("CHAR MALLOC & M DONE");*/
1093 tmp_strr += sprintf(tmp_strr, "%016" PRIx64, temp->threadid);
1094
1095 temp = temp->next;
1096
1097 while (temp) {
1098 /*LOG_INFO("INTO GDB THREAD UPDATE WHILE");*/
1099 tmp_strr += sprintf(tmp_strr, ",");
1100 tmp_strr +=
1101 sprintf(tmp_strr, "%016" PRIx64, temp->threadid);
1102 temp = temp->next;
1103 }
1104
1105 /*tmp_str[0] = 0;*/
1106 gdb_put_packet(connection, out_strr, strlen(out_strr));
1107 linux_os->preupdtate_threadid_count =
1108 linux_os->threadid_count - 1;
1109 free(out_strr);
1110 } else
1111 gdb_put_packet(connection, "l", 1);
1112
1113 return ERROR_OK;
1114 }
1115
1116 static int linux_thread_extra_info(struct target *target,
1117 struct connection *connection, char const *packet,
1118 int packet_size)
1119 {
1120 int64_t threadid = 0;
1121 struct linux_os *linux_os = (struct linux_os *)
1122 target->rtos->rtos_specific_params;
1123 sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid);
1124 /*LOG_INFO("lookup extra info for thread %" SCNx64, threadid);*/
1125 struct threads *temp = linux_os->thread_list;
1126
1127 while (temp) {
1128 if (temp->threadid == threadid) {
1129 char *pid = " PID: ";
1130 char *pid_current = "*PID: ";
1131 char *name = "Name: ";
1132 int str_size = strlen(pid) + strlen(name);
1133 char *tmp_str = calloc(1, str_size + 50);
1134 char *tmp_str_ptr = tmp_str;
1135
1136 /* discriminate current task */
1137 if (temp->status == 3)
1138 tmp_str_ptr += sprintf(tmp_str_ptr, "%s",
1139 pid_current);
1140 else
1141 tmp_str_ptr += sprintf(tmp_str_ptr, "%s", pid);
1142
1143 tmp_str_ptr += sprintf(tmp_str_ptr, "%d, ", (int)temp->pid);
1144 sprintf(tmp_str_ptr, "%s", name);
1145 sprintf(tmp_str_ptr, "%s", temp->name);
1146 char *hex_str = calloc(1, strlen(tmp_str) * 2 + 1);
1147 size_t pkt_len = hexify(hex_str, (const uint8_t *)tmp_str,
1148 strlen(tmp_str), strlen(tmp_str) * 2 + 1);
1149 gdb_put_packet(connection, hex_str, pkt_len);
1150 free(hex_str);
1151 free(tmp_str);
1152 return ERROR_OK;
1153 }
1154
1155 temp = temp->next;
1156 }
1157
1158 LOG_INFO("thread not found");
1159 return ERROR_OK;
1160 }
1161
1162 static int linux_gdb_t_packet(struct connection *connection,
1163 struct target *target, char const *packet, int packet_size)
1164 {
1165 int64_t threadid;
1166 struct linux_os *linux_os = (struct linux_os *)
1167 target->rtos->rtos_specific_params;
1168 int retval = ERROR_OK;
1169 sscanf(packet, "T%" SCNx64, &threadid);
1170
1171 if (linux_os->threads_needs_update == 0) {
1172 struct threads *temp = linux_os->thread_list;
1173 struct threads *prev = NULL;
1174
1175 while (temp) {
1176 if (temp->threadid == threadid) {
1177 if (temp->status != 0) {
1178 gdb_put_packet(connection, "OK", 2);
1179 return ERROR_OK;
1180 } else {
1181 /* delete item in the list */
1182 linux_os->thread_list =
1183 liste_del_task(linux_os->thread_list,
1184 &temp, prev);
1185 linux_os->thread_count--;
1186 gdb_put_packet(connection, "E01", 3);
1187 return ERROR_OK;
1188 }
1189 }
1190
1191 /* for deletion */
1192 prev = temp;
1193 temp = temp->next;
1194 }
1195
1196 LOG_INFO("gdb requested status on non existing thread");
1197 gdb_put_packet(connection, "E01", 3);
1198 return ERROR_OK;
1199
1200 } else {
1201 retval = linux_task_update(target, 1);
1202 struct threads *temp = linux_os->thread_list;
1203
1204 while (temp) {
1205 if (temp->threadid == threadid) {
1206 if (temp->status == 1) {
1207 gdb_put_packet(connection, "OK", 2);
1208 return ERROR_OK;
1209 } else {
1210 gdb_put_packet(connection, "E01", 3);
1211 return ERROR_OK;
1212 }
1213 }
1214
1215 temp = temp->next;
1216 }
1217 }
1218
1219 return retval;
1220 }
1221
1222 static int linux_gdb_h_packet(struct connection *connection,
1223 struct target *target, char const *packet, int packet_size)
1224 {
1225 struct linux_os *linux_os = (struct linux_os *)
1226 target->rtos->rtos_specific_params;
1227 struct current_thread *ct = linux_os->current_threads;
1228
1229 /* select to display the current thread of the selected target */
1230 while ((ct) && (ct->core_id != target->coreid))
1231 ct = ct->next;
1232
1233 int64_t current_gdb_thread_rq;
1234
1235 if (linux_os->threads_lookup == 1) {
1236 if ((ct) && (ct->threadid == -1)) {
1237 ct = linux_os->current_threads;
1238
1239 while ((ct) && (ct->threadid == -1))
1240 ct = ct->next;
1241 }
1242
1243 if (!ct) {
1244 /* no current thread can be identified
1245 * any way with smp */
1246 LOG_INFO("no current thread identified");
1247 /* attempt to display the name of the 2 threads identified with
1248 * get_current */
1249 struct threads t;
1250 ct = linux_os->current_threads;
1251
1252 while ((ct) && (ct->threadid == -1)) {
1253 t.base_addr = ct->TS;
1254 get_name(target, &t);
1255 LOG_INFO("name of unidentified thread %s",
1256 t.name);
1257 ct = ct->next;
1258 }
1259
1260 gdb_put_packet(connection, "OK", 2);
1261 return ERROR_OK;
1262 }
1263
1264 if (packet[1] == 'g') {
1265 sscanf(packet, "Hg%16" SCNx64, &current_gdb_thread_rq);
1266
1267 if (current_gdb_thread_rq == 0) {
1268 target->rtos->current_threadid = ct->threadid;
1269 gdb_put_packet(connection, "OK", 2);
1270 } else {
1271 target->rtos->current_threadid =
1272 current_gdb_thread_rq;
1273 gdb_put_packet(connection, "OK", 2);
1274 }
1275 } else if (packet[1] == 'c') {
1276 sscanf(packet, "Hc%16" SCNx64, &current_gdb_thread_rq);
1277
1278 if ((current_gdb_thread_rq == 0) ||
1279 (current_gdb_thread_rq == ct->threadid)) {
1280 target->rtos->current_threadid = ct->threadid;
1281 gdb_put_packet(connection, "OK", 2);
1282 } else
1283 gdb_put_packet(connection, "E01", 3);
1284 }
1285 } else
1286 gdb_put_packet(connection, "OK", 2);
1287
1288 return ERROR_OK;
1289 }
1290
1291 static int linux_thread_packet(struct connection *connection, char const *packet,
1292 int packet_size)
1293 {
1294 int retval = ERROR_OK;
1295 struct current_thread *ct;
1296 struct target *target = get_target_from_connection(connection);
1297 struct linux_os *linux_os = (struct linux_os *)
1298 target->rtos->rtos_specific_params;
1299
1300 switch (packet[0]) {
1301 case 'T': /* Is thread alive?*/
1302
1303 linux_gdb_t_packet(connection, target, packet, packet_size);
1304 break;
1305 case 'H': /* Set current thread */
1306 /* ( 'c' for step and continue, 'g' for all other operations )*/
1307 /*LOG_INFO(" H packet received '%s'", packet);*/
1308 linux_gdb_h_packet(connection, target, packet, packet_size);
1309 break;
1310 case 'q':
1311
1312 if (strncmp(packet, "qSymbol", 7) == 0) {
1313 if (rtos_qsymbol(connection, packet, packet_size) == 1) {
1314 linux_compute_virt2phys(target,
1315 target->rtos->symbols[INIT_TASK].address);
1316 }
1317
1318 break;
1319 } else if (strncmp(packet, "qfThreadInfo", 12) == 0) {
1320 if (!linux_os->thread_list) {
1321 retval = linux_gdb_thread_packet(target,
1322 connection,
1323 packet,
1324 packet_size);
1325 break;
1326 } else {
1327 retval = linux_gdb_thread_update(target,
1328 connection,
1329 packet,
1330 packet_size);
1331 break;
1332 }
1333 } else if (strncmp(packet, "qsThreadInfo", 12) == 0) {
1334 gdb_put_packet(connection, "l", 1);
1335 break;
1336 } else if (strncmp(packet, "qThreadExtraInfo,", 17) == 0) {
1337 linux_thread_extra_info(target, connection, packet,
1338 packet_size);
1339 break;
1340 } else {
1341 retval = GDB_THREAD_PACKET_NOT_CONSUMED;
1342 break;
1343 }
1344
1345 case 'Q':
1346 /* previously response was : thread not found
1347 * gdb_put_packet(connection, "E01", 3); */
1348 retval = GDB_THREAD_PACKET_NOT_CONSUMED;
1349 break;
1350 case 'c':
1351 case 's': {
1352 if (linux_os->threads_lookup == 1) {
1353 ct = linux_os->current_threads;
1354
1355 while ((ct) && (ct->core_id) != target->coreid)
1356 ct = ct->next;
1357
1358 if ((ct) && (ct->threadid == -1)) {
1359 ct = linux_os->current_threads;
1360
1361 while ((ct) && (ct->threadid == -1))
1362 ct = ct->next;
1363 }
1364
1365 if ((ct) && (ct->threadid !=
1366 target->rtos->current_threadid)
1367 && (target->rtos->current_threadid != -1))
1368 LOG_WARNING("WARNING! current GDB thread do not match "
1369 "current thread running. "
1370 "Switch thread in GDB to threadid %d",
1371 (int)ct->threadid);
1372
1373 LOG_INFO("threads_needs_update = 1");
1374 linux_os->threads_needs_update = 1;
1375 }
1376 }
1377
1378 /* if a packet handler returned an error, exit input loop */
1379 if (retval != ERROR_OK)
1380 return retval;
1381 }
1382
1383 return retval;
1384 }
1385
1386 static int linux_os_smp_init(struct target *target)
1387 {
1388 struct target_list *head;
1389 /* keep only target->rtos */
1390 struct rtos *rtos = target->rtos;
1391 struct linux_os *os_linux =
1392 (struct linux_os *)rtos->rtos_specific_params;
1393 struct current_thread *ct;
1394
1395 foreach_smp_target(head, target->smp_targets) {
1396 if (head->target->rtos != rtos) {
1397 struct linux_os *smp_os_linux =
1398 (struct linux_os *)head->target->rtos->rtos_specific_params;
1399 /* remap smp target on rtos */
1400 free(head->target->rtos);
1401 head->target->rtos = rtos;
1402 /* reuse allocated ct */
1403 ct = smp_os_linux->current_threads;
1404 ct->threadid = -1;
1405 ct->TS = 0xdeadbeef;
1406 ct->core_id = head->target->coreid;
1407 os_linux->current_threads =
1408 add_current_thread(os_linux->current_threads, ct);
1409 os_linux->nr_cpus++;
1410 free(smp_os_linux);
1411 }
1412 }
1413
1414 return ERROR_OK;
1415 }
1416
1417 static int linux_os_create(struct target *target)
1418 {
1419 struct linux_os *os_linux = calloc(1, sizeof(struct linux_os));
1420 struct current_thread *ct = calloc(1, sizeof(struct current_thread));
1421 LOG_INFO("linux os creation\n");
1422 os_linux->init_task_addr = 0xdeadbeef;
1423 os_linux->name = "linux";
1424 os_linux->thread_list = NULL;
1425 os_linux->thread_count = 0;
1426 target->rtos->current_threadid = -1;
1427 os_linux->nr_cpus = 1;
1428 os_linux->threads_lookup = 0;
1429 os_linux->threads_needs_update = 0;
1430 os_linux->threadid_count = 1;
1431 os_linux->current_threads = NULL;
1432 target->rtos->rtos_specific_params = os_linux;
1433 ct->core_id = target->coreid;
1434 ct->threadid = -1;
1435 ct->TS = 0xdeadbeef;
1436 os_linux->current_threads =
1437 add_current_thread(os_linux->current_threads, ct);
1438 /* overload rtos thread default handler */
1439 target->rtos->gdb_thread_packet = linux_thread_packet;
1440 /* initialize a default virt 2 phys translation */
1441 os_linux->phys_mask = ~0xc0000000;
1442 os_linux->phys_base = 0x0;
1443 return JIM_OK;
1444 }
1445
1446 static char *linux_ps_command(struct target *target)
1447 {
1448 struct linux_os *linux_os = (struct linux_os *)
1449 target->rtos->rtos_specific_params;
1450 int retval = ERROR_OK;
1451 char *display;
1452
1453 if (linux_os->threads_lookup == 0)
1454 retval = linux_get_tasks(target, 1);
1455 else {
1456 if (linux_os->threads_needs_update != 0)
1457 retval = linux_task_update(target, 0);
1458 }
1459
1460 if (retval == ERROR_OK) {
1461 struct threads *temp = linux_os->thread_list;
1462 char *tmp;
1463 LOG_INFO("allocation for %d threads line",
1464 linux_os->thread_count);
1465 display = calloc((linux_os->thread_count + 2) * 80, 1);
1466
1467 if (!display)
1468 goto error;
1469
1470 tmp = display;
1471 tmp += sprintf(tmp, "PID\t\tCPU\t\tASID\t\tNAME\n");
1472 tmp += sprintf(tmp, "---\t\t---\t\t----\t\t----\n");
1473
1474 while (temp) {
1475 if (temp->status) {
1476 if (temp->context)
1477 tmp +=
1478 sprintf(tmp,
1479 "%" PRIu32 "\t\t%" PRIu32 "\t\t%" PRIx32 "\t\t%s\n",
1480 temp->pid, temp->oncpu,
1481 temp->asid, temp->name);
1482 else
1483 tmp +=
1484 sprintf(tmp,
1485 "%" PRIu32 "\t\t%" PRIu32 "\t\t%" PRIx32 "\t\t%s\n",
1486 temp->pid, temp->oncpu,
1487 temp->asid, temp->name);
1488 }
1489
1490 temp = temp->next;
1491 }
1492
1493 return display;
1494 }
1495
1496 error:
1497 display = calloc(40, 1);
1498 sprintf(display, "linux_ps_command failed\n");
1499 return display;
1500 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)