Subversion Repositories HelenOS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2008 Jiri Svoboda
  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.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup debug
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34.  
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <assert.h>
  38. #include <sys/types.h>
  39. #include <errno.h>
  40. #include <udebug.h>
  41.  
  42. #include "../../cons.h"
  43. #include "../../main.h"
  44. #include "../../breakpoint.h"
  45. #include "../../include/arch.h"
  46. #include "../../include/arch/arch.h"
  47. #include "idec.h"
  48.  
  49. static istate_t istate;
  50.  
  51. int idec_breakpoint_set(breakpoint_t *b)
  52. {
  53.     bstore_initialize(&b->arch.bs);
  54.     bstore_initialize(&b->arch.next_bs[0]);
  55.     bstore_initialize(&b->arch.next_bs[1]);
  56.  
  57.     return bstore_push(&b->arch.bs, b->addr, OPCODE_BREAK);
  58. }
  59.  
  60. int idec_breakpoint_remove(breakpoint_t *b)
  61. {
  62.     return bstore_pop(&b->arch.bs);
  63. }
  64.  
  65. static void _ev_breakpoint(thash_t thread_hash)
  66. {
  67.     breakpoint_t *b;
  68.     dthread_t *dt;
  69.     int rc, n_next, i;
  70.     uint32_t epc;
  71.     uintptr_t brk_addr;
  72.     uintptr_t next_addr[2];
  73.     uint32_t brkp;
  74.  
  75.     brkp = OPCODE_BREAK;
  76.  
  77.     cons_printf("arch_event_breakpoint\n");
  78.  
  79.     rc = udebug_regs_read(app_phone, thread_hash, &istate);
  80.     cons_printf("udebug_regs_read -> %d\n", rc);
  81.     epc = istate_get_pc(&istate);
  82.     cons_printf("EPC was 0x%08x\n", epc);
  83.     brk_addr = epc;
  84.  
  85.     dt = dthread_get();
  86.  
  87.     if (active_bkpt != NULL) {
  88.         assert(active_bkpt->arch.bs.address == brk_addr);
  89.         b = active_bkpt;
  90.  
  91.         /* A breakpoint-restoring BRK has been hit */
  92.         cons_printf("restoring breakpoint %d\n", b->id);
  93.         for (i = 0; i < b->arch.n_next; ++i) {
  94.             rc = bstore_pop(&b->arch.next_bs[i]);
  95.             if (rc != 0) return;
  96.         }
  97.  
  98.         rc = bstore_push(&b->arch.bs, b->addr, OPCODE_BREAK);
  99.         if (rc != 0) return;
  100.         active_bkpt = NULL;
  101.         return;
  102.     }
  103.  
  104.     b = breakpoint_find_by_addr(brk_addr);
  105.     if (b == NULL) {
  106.         cons_printf("Unrecognized breakpoint at 0x%lx\n", brk_addr);
  107.     }
  108.  
  109.     /* A breakpoint has been hit */
  110.     cons_printf("breakpoint_hit...\n");
  111.     breakpoint_hit(b);
  112.  
  113.     /* While in breakpoint_hit(), singlestep was activated */
  114.     if (dt->arch.singlestep) return;
  115.  
  116.     cons_printf("move breakpoint\b");
  117.     rc = bstore_pop(&b->arch.bs);
  118.     if (rc != 0) return;
  119.  
  120.     n_next = get_next_addr(dt, brk_addr, next_addr);
  121.     if (n_next < 0) return;
  122.  
  123.     /*
  124.      * There could be another breakpoint at next_addr,
  125.      * but that's okay. We'll pop the active breakpoint bs
  126.      * before doing anything else.
  127.      */
  128.     for (i = 0; i < n_next; ++i) {
  129.         rc = bstore_push(&b->arch.next_bs[i], next_addr[i],
  130.             OPCODE_BREAK);
  131.         if (rc != 0) return;
  132.     }
  133.     b->arch.n_next = n_next;
  134.  
  135.     active_bkpt = b;
  136.     b->active = true;
  137.  
  138.     cons_printf("end_hit...\n");
  139. }
  140.  
  141.  
  142. static void _ev_singlestep(thash_t thread_hash)
  143. {
  144.     dthread_t *dt;
  145.     int rc, i;
  146.     uint32_t epc;
  147.     int brk_addr;
  148.     uint32_t brkp;
  149.  
  150.     dt = dthread_get();
  151.  
  152.     assert(active_bkpt == NULL);
  153.     assert(dt->arch.singlestep);
  154.     brkp = OPCODE_BREAK;
  155.  
  156.     cons_printf("arch_event_breakpoint\n");
  157.  
  158.     rc = udebug_regs_read(app_phone, thread_hash, &istate);
  159.     cons_printf("udebug_regs_read -> %d\n", rc);
  160.     epc = istate_get_pc(&istate);
  161.     cons_printf("EPC was 0x%08x\n", epc);
  162.     brk_addr = epc;
  163.  
  164.     if (dt->arch.cur.valid) {
  165.         cons_printf("restore breakpoint BREAK\n");
  166.         rc = bstore_pop(&dt->arch.cur);
  167.     }
  168.  
  169.     cons_printf("\nclear singlestep BREAKs\n");
  170.     for (i = 0; i < dt->arch.n_next; ++i) {
  171.         rc = bstore_pop(&dt->arch.next[i]);
  172.         if (rc != 0) return;
  173.     }
  174.  
  175.     dt->arch.singlestep = false;
  176.  
  177.     singlestep_hit();
  178. }
  179.  
  180.  
  181. void idec_event_breakpoint(thash_t thread_hash)
  182. {
  183.     dthread_t *dt;
  184.  
  185.     dt = dthread_get();
  186.     if (dt->arch.singlestep) {
  187.         _ev_singlestep(thread_hash);
  188.     } else {
  189.         _ev_breakpoint(thread_hash);
  190.     }
  191. }
  192.  
  193. void idec_singlestep(dthread_t *dt)
  194. {
  195.     int rc, i;
  196.     uint32_t epc;
  197.     breakpoint_t *b;
  198.     uint32_t old_instr;
  199.     uintptr_t next_addr[2];
  200.     int n_next;
  201.  
  202.     assert(active_bkpt == NULL);
  203.     assert(dt->arch.singlestep == false);
  204.  
  205.     cons_printf("idec_singlestep(dt)\n");
  206.     rc = udebug_regs_read(app_phone, dt->hash, &istate);
  207.     cons_printf("udebug_regs_read -> %d\n", rc);
  208.     epc = istate_get_pc(&istate);
  209.     cons_printf("EPC was 0x%08x\n", epc);
  210.  
  211.     cons_printf("initial set singlestep\n");
  212.     b = breakpoint_find_by_addr(epc);
  213.     if (b != NULL) {
  214.         /* Cover breakpoint with old instruction */
  215.         old_instr = b->arch.bs.value;
  216.         rc = bstore_push(&dt->arch.cur, epc, old_instr);
  217.         if (rc < 0) return;
  218.     }
  219.  
  220.     n_next = get_next_addr(dt, epc, next_addr);
  221.     if (n_next < 0) return;
  222.  
  223.     /* Cover next instruction(s) with BREAK */
  224.     for (i = 0; i < n_next; ++i) {
  225.         rc = bstore_push(&dt->arch.next[i], next_addr[i], OPCODE_BREAK);
  226.         if (rc != 0) return;
  227.     }
  228.     dt->arch.n_next = n_next;
  229.  
  230.     dt->arch.singlestep = true;
  231.     dthread_resume(dt);
  232. }
  233.  
  234. /** @}
  235.  */
  236.