source: rtems/cpukit/libdebugger/rtems-debugger-threads.c @ 54ac945

Last change on this file since 54ac945 was 54ac945, checked in by Sebastian Huber <sebastian.huber@…>, on Jun 26, 2019 at 5:57:50 AM

libdebugger: Unmap thread priorities

  • Property mode set to 100644
File size: 16.2 KB
Line 
1/*
2 * Copyright (c) 2016-2017 Chris Johns <chrisj@rtems.org>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <errno.h>
28#include <inttypes.h>
29#include <stdlib.h>
30#include <stdio.h>
31
32#include <rtems.h>
33#include <rtems/assoc.h>
34#include <rtems/score/schedulerimpl.h>
35#include <rtems/score/threadimpl.h>
36
37#include <rtems/debugger/rtems-debugger-server.h>
38
39#include "rtems-debugger-target.h"
40#include "rtems-debugger-threads.h"
41
42static const char * const excludes_defaults[] =
43{
44  "TIME",
45  "_BSD",
46  "IRQS",
47  "DBSs",
48  "DBSe",
49  "IDLE",
50};
51
52static void
53rtems_debugger_thread_free(rtems_debugger_threads* threads)
54{
55  rtems_debugger_block_destroy(&threads->current);
56  rtems_debugger_block_destroy(&threads->registers);
57  rtems_debugger_block_destroy(&threads->excludes);
58  rtems_debugger_block_destroy(&threads->stopped);
59  rtems_debugger_block_destroy(&threads->steppers);
60  threads->next = 0;
61}
62
63int
64rtems_debugger_thread_create(void)
65{
66  rtems_debugger_threads* threads;
67  int                     r;
68
69  threads = calloc(1, sizeof(rtems_debugger_threads));
70  if (threads == NULL) {
71    errno = ENOMEM;
72    rtems_debugger_printf("error: rtems-db: thread: threads alloc: (%d) %s\n",
73                          errno, strerror(errno));
74    return -1;
75  }
76
77  r = rtems_debugger_block_create(&threads->current,
78                                  RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
79                                  sizeof(rtems_debugger_thread));
80  if (r < 0) {
81    rtems_debugger_thread_free(threads);
82    free(threads);
83    rtems_debugger_printf("error: rtems-db: thread: current alloc: (%d) %s\n",
84                          errno, strerror(errno));
85    return -1;
86  }
87
88  r = rtems_debugger_block_create(&threads->registers,
89                                  RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
90                                  rtems_debugger_target_reg_table_size());
91  if (r < 0) {
92    rtems_debugger_thread_free(threads);
93    free(threads);
94    rtems_debugger_printf("error: rtems-db: thread: registers alloc: (%d) %s\n",
95                          errno, strerror(errno));
96    return -1;
97  }
98
99  r = rtems_debugger_block_create(&threads->excludes,
100                                  RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
101                                  sizeof(rtems_id));
102  if (r < 0) {
103    rtems_debugger_thread_free(threads);
104    free(threads);
105    rtems_debugger_printf("error: rtems-db: thread: exlcudes alloc: (%d) %s\n",
106                          errno, strerror(errno));
107    return -1;
108  }
109
110  r = rtems_debugger_block_create(&threads->stopped,
111                                  RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
112                                  sizeof(rtems_id));
113  if (r < 0) {
114    rtems_debugger_thread_free(threads);
115    free(threads);
116    rtems_debugger_printf("error: rtems-db: thread: stopped alloc: (%d) %s\n",
117                          errno, strerror(errno));
118    return -1;
119  }
120
121  r = rtems_debugger_block_create(&threads->steppers,
122                                  RTEMS_DEBUGGER_THREAD_BLOCK_SIZE,
123                                  sizeof(rtems_debugger_thread_stepper));
124  if (r < 0) {
125    rtems_debugger_thread_free(threads);
126    free(threads);
127    rtems_debugger_printf("error: rtems-db: thread: steppers alloc: (%d) %s\n",
128                          errno, strerror(errno));
129    return -1;
130  }
131
132  rtems_debugger->threads = threads;
133
134  return rtems_debugger_thread_system_suspend();
135}
136
137int
138rtems_debugger_thread_destroy(void)
139{
140  rtems_debugger_threads* threads = rtems_debugger->threads;
141  rtems_debugger_thread_system_resume(true);
142  rtems_debugger_thread_free(threads);
143  free(threads);
144  rtems_debugger->threads = NULL;
145  return 0;
146}
147
148int
149rtems_debugger_thread_find_index(rtems_id id)
150{
151  rtems_debugger_threads* threads = rtems_debugger->threads;
152  rtems_debugger_thread*  current = rtems_debugger_thread_current(threads);
153  int                     r = -1;
154  if (threads != NULL) {
155    size_t i;
156    for (i = 0; i < threads->current.level; ++i) {
157      if (id == 0 || current[i].id == id) {
158        r = i;
159        break;
160      }
161    }
162  }
163  return r;
164}
165
166static bool
167snapshot_thread(rtems_tcb* tcb, void* arg)
168{
169  rtems_debugger_threads* threads = rtems_debugger->threads;
170  rtems_id                id = tcb->Object.id;
171  char                    name[RTEMS_DEBUGGER_THREAD_NAME_SIZE];
172  bool                    exclude = false;
173  size_t                  i;
174
175  /*
176   * The only time the threads pointer is NULL is a realloc error so we stop
177   * processing threads. There is no way to stop the iterator.
178   */
179  if (rtems_debugger_thread_current(threads) == NULL)
180    return true;
181
182  /*
183   * Filter the threads.
184   */
185  switch (rtems_object_id_get_api(id)) {
186  case OBJECTS_NO_API:
187  case OBJECTS_INTERNAL_API:
188    exclude = true;
189    break;
190  default:
191    rtems_object_get_name(id, sizeof(name), (char*) &name[0]);
192    for (i = 0; i < RTEMS_DEBUGGER_NUMOF(excludes_defaults); ++i) {
193      if (strcmp(excludes_defaults[i], name) == 0) {
194        exclude = true;
195        break;
196      }
197    }
198    break;
199  }
200
201  if (exclude) {
202    rtems_id* excludes;
203    int       r;
204    r = rtems_debugger_block_resize(&threads->excludes);
205    if (r < 0) {
206      rtems_debugger_thread_free(threads);
207      return true;
208    }
209    excludes = rtems_debugger_thread_excludes(threads);
210    excludes[threads->excludes.level++] = id;
211  }
212  else {
213    rtems_debugger_thread* current;
214    uint8_t*               registers;
215    rtems_debugger_thread* thread;
216    int                    r;
217
218    r = rtems_debugger_block_resize(&threads->current);
219    if (r < 0) {
220      rtems_debugger_thread_free(threads);
221      return true;
222    }
223    r = rtems_debugger_block_resize(&threads->registers);
224    if (r < 0) {
225      rtems_debugger_thread_free(threads);
226      return true;
227    }
228
229    current = rtems_debugger_thread_current(threads);
230    registers = rtems_debugger_thread_registers(threads);
231
232    thread = &current[threads->current.level++];
233    thread->registers =
234        &registers[threads->registers.level++ * rtems_debugger_target_reg_table_size()];
235
236    thread->tcb    = tcb;
237    thread->id     = id;
238    thread->flags  = 0;
239    thread->signal = 0;
240    thread->frame  = NULL;
241    memcpy((void*) &thread->name[0], &name[0], sizeof(thread->name));
242
243    /*
244     * See if there is a valid exception stack frame and if the thread is being
245     * debugged.
246     */
247    rtems_debugger_target_exception_thread(thread);
248
249    /*
250     * Exception threads have stopped for breakpoint, segv or other errors.
251     */
252    if (rtems_debugger_thread_flag(thread,
253                                   RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION)) {
254      rtems_id* stopped;
255      r = rtems_debugger_block_resize(&threads->stopped);
256      if (r < 0) {
257        rtems_debugger_thread_free(threads);
258        return true;
259      }
260      stopped = rtems_debugger_thread_stopped(threads);
261      stopped[threads->stopped.level++] = id;
262    }
263    else {
264      rtems_status_code sc;
265      sc = rtems_task_suspend(id);
266      if (sc != RTEMS_SUCCESSFUL && sc != RTEMS_ALREADY_SUSPENDED) {
267        rtems_debugger_printf("error: rtems-db: thread: suspend: %08" PRIx32 ": %s\n",
268                              id, rtems_status_text(sc));
269        r = -1;
270      }
271    }
272
273    /*
274     * Read the target registers into the thread register array.
275     */
276    rtems_debugger_target_read_regs(thread);
277
278    if (rtems_debugger_server_flag(RTEMS_DEBUGGER_FLAG_VERBOSE))
279      rtems_debugger_printf("rtems-db: sys: thd: %08" PRIx32 ": signal: %d\n",
280                            id, thread->signal);
281
282    /*
283     * Pick up the first non-zero signal.
284     */
285    if (rtems_debugger->signal == 0) {
286      rtems_debugger->signal = thread->signal;
287    }
288  }
289
290  return false;
291}
292
293int
294rtems_debugger_thread_system_suspend(void)
295{
296  rtems_debugger_threads* threads = rtems_debugger->threads;
297  int                     r = -1;
298  if (threads != NULL && rtems_debugger_thread_current(threads) != NULL) {
299    if (rtems_debugger_verbose())
300      rtems_debugger_printf("rtems-db: sys:    : suspending\n");
301    r = rtems_debugger_target_swbreak_remove();
302    if (r == 0)
303      r = rtems_debugger_target_hwbreak_remove();
304    if (r == 0) {
305      rtems_debugger_thread* current;
306      threads->current.level = 0;
307      threads->registers.level = 0;
308      threads->stopped.level = 0;
309      threads->excludes.level = 0;
310      threads->steppers.level = 0;
311      rtems_task_iterate(snapshot_thread, NULL);
312      current = rtems_debugger_thread_current(threads);
313      if (current == NULL) {
314        rtems_debugger_printf("error: rtems-db: thread: snapshot: (%d) %s\n",
315                              errno, strerror(errno));
316        r = -1;
317      }
318      else {
319        rtems_id* stopped;
320        /*
321         * If there are no stopped threads pick the first one in the current
322         * table and return that.
323         */
324        threads->selector_gen = 0;
325        threads->selector_cont = 0;
326        stopped = rtems_debugger_thread_stopped(threads);
327        if (threads->stopped.level == 0 && threads->current.level > 0) {
328          stopped[threads->stopped.level++] = current[0].id;
329        }
330        if (threads->stopped.level > 0) {
331          threads->selector_gen =
332            rtems_debugger_thread_find_index(stopped[0]);
333          if (threads->selector_gen < 0)
334            threads->selector_gen = 0;
335        }
336      }
337    }
338    else {
339      errno = EIO;
340    }
341  }
342  return r;
343}
344
345int
346rtems_debugger_thread_system_resume(bool detaching)
347{
348  rtems_debugger_threads* threads = rtems_debugger->threads;
349  rtems_debugger_thread*  current;
350  int                     r = 0;
351  current = rtems_debugger_thread_current(threads);
352  if (threads != NULL && current != NULL) {
353    size_t i;
354    if (rtems_debugger_verbose())
355      rtems_debugger_printf("rtems-db: sys:    : resuming\n");
356    if (!detaching) {
357      r = rtems_debugger_target_swbreak_insert();
358      if (r == 0)
359        r = rtems_debugger_target_hwbreak_insert();
360    }
361    if (r == 0) {
362      for (i = 0; i < threads->current.level; ++i) {
363        rtems_debugger_thread* thread = &current[i];
364        rtems_status_code      sc;
365        int                    rr;
366        /*
367         * Check if resuming, which can be continuing, a step, or stepping a
368         * range.
369         */
370        if (detaching ||
371            rtems_debugger_thread_flag(thread,
372                                       RTEMS_DEBUGGER_THREAD_FLAG_RESUME)) {
373          if (!detaching) {
374            rr = rtems_debugger_target_write_regs(thread);
375            if (rr < 0 && r == 0)
376              r = rr;
377            if (rtems_debugger_thread_flag(thread,
378                                           RTEMS_DEBUGGER_THREAD_FLAG_STEP_INSTR)) {
379              rr = rtems_debugger_target_thread_stepping(thread);
380              if (rr < 0 && r == 0)
381                r = rr;
382            }
383          }
384          if (rtems_debugger_verbose())
385            rtems_debugger_printf("rtems-db: sys:    : resume: 0x%08" PRIx32 "\n",
386                                  thread->id);
387          if (rtems_debugger_thread_flag(thread,
388                                         RTEMS_DEBUGGER_THREAD_FLAG_EXCEPTION)) {
389              rtems_debugger_target_exception_thread_resume(thread);
390          } else {
391              sc = rtems_task_resume(thread->id);
392              if (sc != RTEMS_SUCCESSFUL) {
393                  rtems_debugger_printf("error: rtems-db: thread: resume: %08" PRIx32 ": %s\n",
394                                        thread->id, rtems_status_text(sc));
395              }
396          }
397          thread->flags &= ~(RTEMS_DEBUGGER_THREAD_FLAG_CONTINUE |
398                             RTEMS_DEBUGGER_THREAD_FLAG_STEP);
399          thread->signal = 0;
400        }
401      }
402      /*
403       * Excludes are not cleared so the exception handler can find the
404       * excluded thread.
405       */
406      threads->current.level = 0;
407      threads->registers.level = 0;
408      threads->stopped.level = 0;
409    }
410    else {
411      r = -1;
412      errno = EIO;
413    }
414  }
415  return r;
416}
417
418int
419rtems_debugger_thread_continue(rtems_debugger_thread* thread)
420{
421  thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_CONTINUE;
422  return 0;
423}
424
425int
426rtems_debugger_thread_continue_all(void)
427{
428  rtems_debugger_threads* threads = rtems_debugger->threads;
429  rtems_debugger_thread*  current;
430  int                     r = 0;
431  current = rtems_debugger_thread_current(threads);
432  if (threads != NULL && current != NULL) {
433    size_t i;
434    for (i = 0; i < threads->current.level; ++i) {
435      rtems_debugger_thread* thread = &current[i];
436      if (!rtems_debugger_thread_flag(thread,
437                                      RTEMS_DEBUGGER_THREAD_FLAG_STEP_INSTR)) {
438        r = rtems_debugger_thread_continue(thread);
439        if (r < 0)
440          break;
441      }
442    }
443  }
444  else {
445    r = -1;
446    errno = EIO;
447  }
448  return r;
449}
450
451int
452rtems_debugger_thread_step(rtems_debugger_thread* thread)
453{
454  thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_STEP;
455  return 0;
456}
457
458int
459rtems_debugger_thread_stepping(rtems_debugger_thread* thread,
460                               DB_UINT                start,
461                               DB_UINT                end)
462{
463  /* add lock */
464  rtems_debugger_threads*        threads = rtems_debugger->threads;
465  rtems_debugger_thread_stepper* stepper;
466  int                            r;
467  /*
468   * The resize will automatically extend the block when we are full. The
469   * steppers are cleared in suspend by setting the level to 0.
470   */
471  r = rtems_debugger_block_resize(&threads->steppers);
472  if (r < 0) {
473    rtems_debugger_thread_free(threads);
474    return -1;
475  }
476  stepper = rtems_debugger_thread_steppers(threads);
477  stepper = &stepper[threads->steppers.level];
478  stepper->thread = thread;
479  stepper->start = start;
480  stepper->end = end;
481  threads->steppers.level++;
482  thread->flags |= RTEMS_DEBUGGER_THREAD_FLAG_STEPPING;
483  return 0;
484}
485
486const rtems_debugger_thread_stepper*
487rtems_debugger_thread_is_stepping(rtems_id id, DB_UINT pc)
488{
489  /* add lock */
490  rtems_debugger_threads*        threads = rtems_debugger->threads;
491  rtems_debugger_thread_stepper* stepper;
492  size_t                         i;
493  stepper = rtems_debugger_thread_steppers(threads);
494  for (i = 0; i < threads->steppers.level; ++i, ++stepper) {
495    if (stepper->thread->id == id) {
496      if (pc == stepper->start || (pc > stepper->start && pc < stepper->end))
497        return stepper;
498      break;
499    }
500  }
501  return NULL;
502}
503
504int
505rtems_debugger_thread_current_priority(rtems_debugger_thread* thread)
506{
507  return SCHEDULER_PRIORITY_UNMAP(_Thread_Get_priority(thread->tcb));
508}
509
510int
511rtems_debugger_thread_real_priority(rtems_debugger_thread* thread)
512{
513  return SCHEDULER_PRIORITY_UNMAP(thread->tcb->Real_priority.priority);
514}
515
516int
517rtems_debugger_thread_state(rtems_debugger_thread* thread)
518{
519  return thread->tcb->current_state;
520}
521
522int
523rtems_debugger_thread_state_str(rtems_debugger_thread* thread,
524                                char*                  buf,
525                                size_t                 size)
526{
527  rtems_assoc_thread_states_to_string(thread->tcb->current_state, buf, size);
528  return 0;
529}
530
531unsigned long
532rtems_debugger_thread_stack_size(rtems_debugger_thread* thread)
533{
534  return thread->tcb->Start.Initial_stack.size;
535}
536
537void*
538rtems_debugger_thread_stack_area(rtems_debugger_thread* thread)
539{
540  return thread->tcb->Start.Initial_stack.area;
541}
Note: See TracBrowser for help on using the repository browser.