14e98e3e1Schristos /* Generic simulator watchpoint support. 2*88241920Schristos Copyright (C) 1997-2024 Free Software Foundation, Inc. 34e98e3e1Schristos Contributed by Cygnus Support. 44e98e3e1Schristos 54e98e3e1Schristos This file is part of GDB, the GNU debugger. 64e98e3e1Schristos 74e98e3e1Schristos This program is free software; you can redistribute it and/or modify 84e98e3e1Schristos it under the terms of the GNU General Public License as published by 94e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 104e98e3e1Schristos (at your option) any later version. 114e98e3e1Schristos 124e98e3e1Schristos This program is distributed in the hope that it will be useful, 134e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 144e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 154e98e3e1Schristos GNU General Public License for more details. 164e98e3e1Schristos 174e98e3e1Schristos You should have received a copy of the GNU General Public License 184e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 194e98e3e1Schristos 204b169a6bSchristos /* This must come before any other includes. */ 214b169a6bSchristos #include "defs.h" 224e98e3e1Schristos 234e98e3e1Schristos #include <ctype.h> 248dffb485Schristos #include <stdio.h> 254e98e3e1Schristos #include <stdlib.h> 264b169a6bSchristos #include <string.h> 274b169a6bSchristos 284b169a6bSchristos #include "libiberty.h" 294b169a6bSchristos 304b169a6bSchristos #include "sim-main.h" 314b169a6bSchristos #include "sim-options.h" 324b169a6bSchristos #include "sim-signal.h" 334b169a6bSchristos #include "sim-assert.h" 344e98e3e1Schristos 354e98e3e1Schristos enum { 364e98e3e1Schristos OPTION_WATCH_DELETE = OPTION_START, 374e98e3e1Schristos 384e98e3e1Schristos OPTION_WATCH_INFO, 394e98e3e1Schristos OPTION_WATCH_CLOCK, 404e98e3e1Schristos OPTION_WATCH_CYCLES, 414e98e3e1Schristos OPTION_WATCH_PC, 424e98e3e1Schristos 434e98e3e1Schristos OPTION_WATCH_OP, 444e98e3e1Schristos }; 454e98e3e1Schristos 464e98e3e1Schristos 474e98e3e1Schristos /* Break an option number into its op/int-nr */ 484e98e3e1Schristos static watchpoint_type 494e98e3e1Schristos option_to_type (SIM_DESC sd, 504e98e3e1Schristos int option) 514e98e3e1Schristos { 524e98e3e1Schristos sim_watchpoints *watch = STATE_WATCHPOINTS (sd); 534e98e3e1Schristos watchpoint_type type = ((option - OPTION_WATCH_OP) 544e98e3e1Schristos / (watch->nr_interrupts + 1)); 554e98e3e1Schristos SIM_ASSERT (type >= 0 && type < nr_watchpoint_types); 564e98e3e1Schristos return type; 574e98e3e1Schristos } 584e98e3e1Schristos 594e98e3e1Schristos static int 604e98e3e1Schristos option_to_interrupt_nr (SIM_DESC sd, 614e98e3e1Schristos int option) 624e98e3e1Schristos { 634e98e3e1Schristos sim_watchpoints *watch = STATE_WATCHPOINTS (sd); 644e98e3e1Schristos int interrupt_nr = ((option - OPTION_WATCH_OP) 654e98e3e1Schristos % (watch->nr_interrupts + 1)); 664e98e3e1Schristos return interrupt_nr; 674e98e3e1Schristos } 684e98e3e1Schristos 694e98e3e1Schristos static int 704e98e3e1Schristos type_to_option (SIM_DESC sd, 714e98e3e1Schristos watchpoint_type type, 724e98e3e1Schristos int interrupt_nr) 734e98e3e1Schristos { 744e98e3e1Schristos sim_watchpoints *watch = STATE_WATCHPOINTS (sd); 754e98e3e1Schristos return ((type * (watch->nr_interrupts + 1)) 764e98e3e1Schristos + interrupt_nr 774e98e3e1Schristos + OPTION_WATCH_OP); 784e98e3e1Schristos } 794e98e3e1Schristos 804e98e3e1Schristos 814e98e3e1Schristos /* Delete one or more watchpoints. Fail if no watchpoints were found */ 824e98e3e1Schristos 834e98e3e1Schristos static SIM_RC 844e98e3e1Schristos do_watchpoint_delete (SIM_DESC sd, 854e98e3e1Schristos int ident, 864e98e3e1Schristos watchpoint_type type) 874e98e3e1Schristos { 884e98e3e1Schristos sim_watchpoints *watch = STATE_WATCHPOINTS (sd); 894e98e3e1Schristos sim_watch_point **entry = &watch->points; 904e98e3e1Schristos SIM_RC status = SIM_RC_FAIL; 914e98e3e1Schristos while ((*entry) != NULL) 924e98e3e1Schristos { 934e98e3e1Schristos if ((*entry)->ident == ident 944e98e3e1Schristos || (*entry)->type == type) 954e98e3e1Schristos { 964e98e3e1Schristos sim_watch_point *dead = (*entry); 974e98e3e1Schristos (*entry) = (*entry)->next; 984e98e3e1Schristos sim_events_deschedule (sd, dead->event); 994e98e3e1Schristos free (dead); 1004e98e3e1Schristos status = SIM_RC_OK; 1014e98e3e1Schristos } 1024e98e3e1Schristos else 1034e98e3e1Schristos entry = &(*entry)->next; 1044e98e3e1Schristos } 1054e98e3e1Schristos return status; 1064e98e3e1Schristos } 1074e98e3e1Schristos 1084e98e3e1Schristos static const char * 1094e98e3e1Schristos watchpoint_type_to_str (SIM_DESC sd, 1104e98e3e1Schristos watchpoint_type type) 1114e98e3e1Schristos { 1124e98e3e1Schristos switch (type) 1134e98e3e1Schristos { 1144e98e3e1Schristos case pc_watchpoint: 1154e98e3e1Schristos return "pc"; 1164e98e3e1Schristos case clock_watchpoint: 1174e98e3e1Schristos return "clock"; 1184e98e3e1Schristos case cycles_watchpoint: 1194e98e3e1Schristos return "cycles"; 1204e98e3e1Schristos case invalid_watchpoint: 1214e98e3e1Schristos case nr_watchpoint_types: 1224e98e3e1Schristos return "(invalid-type)"; 1234e98e3e1Schristos } 1244e98e3e1Schristos return NULL; 1254e98e3e1Schristos } 1264e98e3e1Schristos 1274e98e3e1Schristos static const char * 1284e98e3e1Schristos interrupt_nr_to_str (SIM_DESC sd, 1294e98e3e1Schristos int interrupt_nr) 1304e98e3e1Schristos { 1314e98e3e1Schristos sim_watchpoints *watch = STATE_WATCHPOINTS (sd); 1324e98e3e1Schristos if (interrupt_nr < 0) 1334e98e3e1Schristos return "(invalid-interrupt)"; 1344e98e3e1Schristos else if (interrupt_nr >= watch->nr_interrupts) 1354e98e3e1Schristos return "breakpoint"; 1364e98e3e1Schristos else 1374e98e3e1Schristos return watch->interrupt_names[interrupt_nr]; 1384e98e3e1Schristos } 1394e98e3e1Schristos 1404e98e3e1Schristos 1414e98e3e1Schristos static void 1424e98e3e1Schristos do_watchpoint_info (SIM_DESC sd) 1434e98e3e1Schristos { 1444e98e3e1Schristos sim_watchpoints *watch = STATE_WATCHPOINTS (sd); 1454e98e3e1Schristos sim_watch_point *point; 1464e98e3e1Schristos sim_io_printf (sd, "Watchpoints:\n"); 1474e98e3e1Schristos for (point = watch->points; point != NULL; point = point->next) 1484e98e3e1Schristos { 1494e98e3e1Schristos sim_io_printf (sd, "%3d: watch %s %s ", 1504e98e3e1Schristos point->ident, 1514e98e3e1Schristos watchpoint_type_to_str (sd, point->type), 1524e98e3e1Schristos interrupt_nr_to_str (sd, point->interrupt_nr)); 1534e98e3e1Schristos if (point->is_periodic) 1544e98e3e1Schristos sim_io_printf (sd, "+"); 1554e98e3e1Schristos if (!point->is_within) 1564e98e3e1Schristos sim_io_printf (sd, "!"); 1574e98e3e1Schristos sim_io_printf (sd, "0x%lx", point->arg0); 1584e98e3e1Schristos if (point->arg1 != point->arg0) 1594e98e3e1Schristos sim_io_printf (sd, ",0x%lx", point->arg1); 1604e98e3e1Schristos sim_io_printf (sd, "\n"); 1614e98e3e1Schristos } 1624e98e3e1Schristos } 1634e98e3e1Schristos 1644e98e3e1Schristos 1654e98e3e1Schristos 1664e98e3e1Schristos static sim_event_handler handle_watchpoint; 1674e98e3e1Schristos 1684e98e3e1Schristos static SIM_RC 1694e98e3e1Schristos schedule_watchpoint (SIM_DESC sd, 1704e98e3e1Schristos sim_watch_point *point) 1714e98e3e1Schristos { 1724e98e3e1Schristos switch (point->type) 1734e98e3e1Schristos { 1744e98e3e1Schristos case pc_watchpoint: 1754b169a6bSchristos point->event = sim_events_watch_pc (sd, 1764e98e3e1Schristos point->is_within, 1774e98e3e1Schristos point->arg0, point->arg1, 1784e98e3e1Schristos /* PC in arg0..arg1 */ 1794e98e3e1Schristos handle_watchpoint, 1804e98e3e1Schristos point); 1814e98e3e1Schristos return SIM_RC_OK; 1824e98e3e1Schristos case clock_watchpoint: 1834e98e3e1Schristos point->event = sim_events_watch_clock (sd, 1844e98e3e1Schristos point->arg0, /* ms time */ 1854e98e3e1Schristos handle_watchpoint, 1864e98e3e1Schristos point); 1874e98e3e1Schristos return SIM_RC_OK; 1884e98e3e1Schristos case cycles_watchpoint: 1894e98e3e1Schristos point->event = sim_events_schedule (sd, 1904e98e3e1Schristos point->arg0, /* time */ 1914e98e3e1Schristos handle_watchpoint, 1924e98e3e1Schristos point); 1934e98e3e1Schristos return SIM_RC_OK; 1944e98e3e1Schristos default: 1954e98e3e1Schristos sim_engine_abort (sd, NULL, NULL_CIA, 1964e98e3e1Schristos "handle_watchpoint - internal error - bad switch"); 1974e98e3e1Schristos return SIM_RC_FAIL; 1984e98e3e1Schristos } 1994e98e3e1Schristos return SIM_RC_OK; 2004e98e3e1Schristos } 2014e98e3e1Schristos 2024e98e3e1Schristos 2034e98e3e1Schristos static void 2044e98e3e1Schristos handle_watchpoint (SIM_DESC sd, void *data) 2054e98e3e1Schristos { 2064e98e3e1Schristos sim_watchpoints *watch = STATE_WATCHPOINTS (sd); 2074e98e3e1Schristos sim_watch_point *point = (sim_watch_point *) data; 2084e98e3e1Schristos int interrupt_nr = point->interrupt_nr; 2094e98e3e1Schristos 2104e98e3e1Schristos if (point->is_periodic) 2114e98e3e1Schristos /* reschedule this event before processing it */ 2124e98e3e1Schristos schedule_watchpoint (sd, point); 2134e98e3e1Schristos else 2144e98e3e1Schristos do_watchpoint_delete (sd, point->ident, invalid_watchpoint); 2154e98e3e1Schristos 2164e98e3e1Schristos if (point->interrupt_nr == watch->nr_interrupts) 2174e98e3e1Schristos sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGINT); 2184e98e3e1Schristos else 2194e98e3e1Schristos watch->interrupt_handler (sd, &watch->interrupt_names[interrupt_nr]); 2204e98e3e1Schristos } 2214e98e3e1Schristos 2224e98e3e1Schristos 2234e98e3e1Schristos static SIM_RC 2244e98e3e1Schristos do_watchpoint_create (SIM_DESC sd, 2254e98e3e1Schristos watchpoint_type type, 2264e98e3e1Schristos int opt, 2274e98e3e1Schristos char *arg) 2284e98e3e1Schristos { 2294e98e3e1Schristos sim_watchpoints *watch = STATE_WATCHPOINTS (sd); 2304e98e3e1Schristos sim_watch_point **point; 2314e98e3e1Schristos 2324e98e3e1Schristos /* create the watchpoint */ 2334e98e3e1Schristos point = &watch->points; 2344e98e3e1Schristos while ((*point) != NULL) 2354e98e3e1Schristos point = &(*point)->next; 2364e98e3e1Schristos (*point) = ZALLOC (sim_watch_point); 2374e98e3e1Schristos 2384e98e3e1Schristos /* fill in the details */ 2394e98e3e1Schristos (*point)->ident = ++(watch->last_point_nr); 2404e98e3e1Schristos (*point)->type = option_to_type (sd, opt); 2414e98e3e1Schristos (*point)->interrupt_nr = option_to_interrupt_nr (sd, opt); 2424e98e3e1Schristos /* prefixes to arg - +== periodic, !==not or outside */ 2434e98e3e1Schristos (*point)->is_within = 1; 2444e98e3e1Schristos while (1) 2454e98e3e1Schristos { 2464e98e3e1Schristos if (arg[0] == '+') 2474e98e3e1Schristos (*point)->is_periodic = 1; 2484e98e3e1Schristos else if (arg[0] == '!') 2494e98e3e1Schristos (*point)->is_within = 0; 2504e98e3e1Schristos else 2514e98e3e1Schristos break; 2524e98e3e1Schristos arg++; 2534e98e3e1Schristos } 2544e98e3e1Schristos 2554e98e3e1Schristos (*point)->arg0 = strtoul (arg, &arg, 0); 2564e98e3e1Schristos if (arg[0] == ',') 2574b169a6bSchristos (*point)->arg1 = strtoul (arg + 1, NULL, 0); 2584e98e3e1Schristos else 2594e98e3e1Schristos (*point)->arg1 = (*point)->arg0; 2604e98e3e1Schristos 2614e98e3e1Schristos /* schedule it */ 2624e98e3e1Schristos schedule_watchpoint (sd, (*point)); 2634e98e3e1Schristos 2644e98e3e1Schristos return SIM_RC_OK; 2654e98e3e1Schristos } 2664e98e3e1Schristos 2674e98e3e1Schristos 2684e98e3e1Schristos static SIM_RC 2694e98e3e1Schristos watchpoint_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, 2704e98e3e1Schristos char *arg, int is_command) 2714e98e3e1Schristos { 2724e98e3e1Schristos if (opt >= OPTION_WATCH_OP) 2734e98e3e1Schristos return do_watchpoint_create (sd, clock_watchpoint, opt, arg); 2744e98e3e1Schristos else 2754e98e3e1Schristos switch (opt) 2764e98e3e1Schristos { 2774e98e3e1Schristos 2784e98e3e1Schristos case OPTION_WATCH_DELETE: 2794e98e3e1Schristos if (isdigit ((int) arg[0])) 2804e98e3e1Schristos { 2814e98e3e1Schristos int ident = strtol (arg, NULL, 0); 2824e98e3e1Schristos if (do_watchpoint_delete (sd, ident, invalid_watchpoint) 2834e98e3e1Schristos != SIM_RC_OK) 2844e98e3e1Schristos { 2854e98e3e1Schristos sim_io_eprintf (sd, "Watchpoint %d not found\n", ident); 2864e98e3e1Schristos return SIM_RC_FAIL; 2874e98e3e1Schristos } 2884e98e3e1Schristos return SIM_RC_OK; 2894e98e3e1Schristos } 2904e98e3e1Schristos else if (strcasecmp (arg, "all") == 0) 2914e98e3e1Schristos { 2924e98e3e1Schristos watchpoint_type type; 2934e98e3e1Schristos for (type = invalid_watchpoint + 1; 2944e98e3e1Schristos type < nr_watchpoint_types; 2954e98e3e1Schristos type++) 2964e98e3e1Schristos { 2974e98e3e1Schristos do_watchpoint_delete (sd, 0, type); 2984e98e3e1Schristos } 2994e98e3e1Schristos return SIM_RC_OK; 3004e98e3e1Schristos } 3014e98e3e1Schristos else if (strcasecmp (arg, "pc") == 0) 3024e98e3e1Schristos { 3034e98e3e1Schristos if (do_watchpoint_delete (sd, 0, pc_watchpoint) 3044e98e3e1Schristos != SIM_RC_OK) 3054e98e3e1Schristos { 3064e98e3e1Schristos sim_io_eprintf (sd, "No PC watchpoints found\n"); 3074e98e3e1Schristos return SIM_RC_FAIL; 3084e98e3e1Schristos } 3094e98e3e1Schristos return SIM_RC_OK; 3104e98e3e1Schristos } 3114e98e3e1Schristos else if (strcasecmp (arg, "clock") == 0) 3124e98e3e1Schristos { 3134e98e3e1Schristos if (do_watchpoint_delete (sd, 0, clock_watchpoint) != SIM_RC_OK) 3144e98e3e1Schristos { 3154e98e3e1Schristos sim_io_eprintf (sd, "No CLOCK watchpoints found\n"); 3164e98e3e1Schristos return SIM_RC_FAIL; 3174e98e3e1Schristos } 3184e98e3e1Schristos return SIM_RC_OK; 3194e98e3e1Schristos } 3204e98e3e1Schristos else if (strcasecmp (arg, "cycles") == 0) 3214e98e3e1Schristos { 3224e98e3e1Schristos if (do_watchpoint_delete (sd, 0, cycles_watchpoint) != SIM_RC_OK) 3234e98e3e1Schristos { 3244e98e3e1Schristos sim_io_eprintf (sd, "No CYCLES watchpoints found\n"); 3254e98e3e1Schristos return SIM_RC_FAIL; 3264e98e3e1Schristos } 3274e98e3e1Schristos return SIM_RC_OK; 3284e98e3e1Schristos } 3294e98e3e1Schristos sim_io_eprintf (sd, "Unknown watchpoint type `%s'\n", arg); 3304e98e3e1Schristos return SIM_RC_FAIL; 3314e98e3e1Schristos 3324e98e3e1Schristos case OPTION_WATCH_INFO: 3334e98e3e1Schristos { 3344e98e3e1Schristos do_watchpoint_info (sd); 3354e98e3e1Schristos return SIM_RC_OK; 3364e98e3e1Schristos } 3374e98e3e1Schristos 3384e98e3e1Schristos default: 3394e98e3e1Schristos sim_io_eprintf (sd, "Unknown watch option %d\n", opt); 3404e98e3e1Schristos return SIM_RC_FAIL; 3414e98e3e1Schristos 3424e98e3e1Schristos } 3434e98e3e1Schristos 3444e98e3e1Schristos } 3454e98e3e1Schristos 3464e98e3e1Schristos 3474e98e3e1Schristos static SIM_RC 3484e98e3e1Schristos sim_watchpoint_init (SIM_DESC sd) 3494e98e3e1Schristos { 3504e98e3e1Schristos sim_watchpoints *watch = STATE_WATCHPOINTS (sd); 3514e98e3e1Schristos sim_watch_point *point; 3524e98e3e1Schristos /* NOTE: Do not need to de-schedule any previous watchpoints as 3534e98e3e1Schristos sim-events has already done this */ 3544e98e3e1Schristos /* schedule any watchpoints enabled by command line options */ 3554e98e3e1Schristos for (point = watch->points; point != NULL; point = point->next) 3564e98e3e1Schristos { 3574e98e3e1Schristos schedule_watchpoint (sd, point); 3584e98e3e1Schristos } 3594e98e3e1Schristos return SIM_RC_OK; 3604e98e3e1Schristos } 3614e98e3e1Schristos 3624e98e3e1Schristos 3634e98e3e1Schristos static const OPTION watchpoint_options[] = 3644e98e3e1Schristos { 3654e98e3e1Schristos { {"watch-delete", required_argument, NULL, OPTION_WATCH_DELETE }, 3664e98e3e1Schristos '\0', "IDENT|all|pc|cycles|clock", "Delete a watchpoint", 3674e98e3e1Schristos watchpoint_option_handler, NULL }, 3684e98e3e1Schristos 3694e98e3e1Schristos { {"watch-info", no_argument, NULL, OPTION_WATCH_INFO }, 3704e98e3e1Schristos '\0', NULL, "List scheduled watchpoints", 3714e98e3e1Schristos watchpoint_option_handler, NULL }, 3724e98e3e1Schristos 3734e98e3e1Schristos { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL } 3744e98e3e1Schristos }; 3754e98e3e1Schristos 3764e98e3e1Schristos static const char *default_interrupt_names[] = { "int", 0, }; 3774e98e3e1Schristos 3784b169a6bSchristos /* This default handler is "good enough" for targets that just want to trap into 3794b169a6bSchristos gdb when watchpoints are hit, and have only configured the STATE_WATCHPOINTS 3804b169a6bSchristos pc field. */ 3814b169a6bSchristos static void 3824b169a6bSchristos default_interrupt_handler (SIM_DESC sd, void *data) 3834b169a6bSchristos { 3844b169a6bSchristos sim_cpu *cpu = STATE_CPU (sd, 0); 3854b169a6bSchristos address_word cia = CPU_PC_GET (cpu); 3864b169a6bSchristos sim_engine_halt (sd, cpu, NULL, cia, sim_stopped, SIM_SIGTRAP); 3874b169a6bSchristos } 3884e98e3e1Schristos 3894e98e3e1Schristos SIM_RC 3904e98e3e1Schristos sim_watchpoint_install (SIM_DESC sd) 3914e98e3e1Schristos { 3924e98e3e1Schristos sim_watchpoints *watch = STATE_WATCHPOINTS (sd); 3934e98e3e1Schristos SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); 3944e98e3e1Schristos /* the basic command set */ 3954e98e3e1Schristos sim_module_add_init_fn (sd, sim_watchpoint_init); 3964e98e3e1Schristos sim_add_option_table (sd, NULL, watchpoint_options); 3974e98e3e1Schristos /* fill in some details */ 3984e98e3e1Schristos if (watch->interrupt_names == NULL) 3994e98e3e1Schristos watch->interrupt_names = default_interrupt_names; 4004b169a6bSchristos if (watch->interrupt_handler == NULL) 4014b169a6bSchristos watch->interrupt_handler = default_interrupt_handler; 4024e98e3e1Schristos watch->nr_interrupts = 0; 4034e98e3e1Schristos while (watch->interrupt_names[watch->nr_interrupts] != NULL) 4044e98e3e1Schristos watch->nr_interrupts++; 4054e98e3e1Schristos /* generate more advansed commands */ 4064e98e3e1Schristos { 4074e98e3e1Schristos OPTION *int_options = NZALLOC (OPTION, 1 + (watch->nr_interrupts + 1) * nr_watchpoint_types); 4084e98e3e1Schristos int interrupt_nr; 4094e98e3e1Schristos for (interrupt_nr = 0; interrupt_nr <= watch->nr_interrupts; interrupt_nr++) 4104e98e3e1Schristos { 4114e98e3e1Schristos watchpoint_type type; 4124e98e3e1Schristos for (type = 0; type < nr_watchpoint_types; type++) 4134e98e3e1Schristos { 4144e98e3e1Schristos char *name; 4154e98e3e1Schristos int nr = interrupt_nr * nr_watchpoint_types + type; 4164e98e3e1Schristos OPTION *option = &int_options[nr]; 4174e98e3e1Schristos if (asprintf (&name, "watch-%s-%s", 4184e98e3e1Schristos watchpoint_type_to_str (sd, type), 4194e98e3e1Schristos interrupt_nr_to_str (sd, interrupt_nr)) < 0) 4204e98e3e1Schristos return SIM_RC_FAIL; 4214e98e3e1Schristos option->opt.name = name; 4224e98e3e1Schristos option->opt.has_arg = required_argument; 4234e98e3e1Schristos option->opt.val = type_to_option (sd, type, interrupt_nr); 4244e98e3e1Schristos option->doc = ""; 4254e98e3e1Schristos option->doc_name = ""; 4264e98e3e1Schristos option->handler = watchpoint_option_handler; 4274e98e3e1Schristos } 4284e98e3e1Schristos } 4294e98e3e1Schristos /* adjust first few entries so that they contain real 4304e98e3e1Schristos documentation, the first entry includes a list of actions. */ 4314e98e3e1Schristos { 4324e98e3e1Schristos const char *prefix = 4334e98e3e1Schristos "Watch the simulator, take ACTION in COUNT cycles (`+' for every COUNT cycles), ACTION is"; 4344e98e3e1Schristos char *doc; 4354e98e3e1Schristos int len = strlen (prefix) + 1; 4364e98e3e1Schristos for (interrupt_nr = 0; interrupt_nr <= watch->nr_interrupts; interrupt_nr++) 4374e98e3e1Schristos len += strlen (interrupt_nr_to_str (sd, interrupt_nr)) + 1; 4384e98e3e1Schristos doc = NZALLOC (char, len); 4394e98e3e1Schristos strcpy (doc, prefix); 4404e98e3e1Schristos for (interrupt_nr = 0; interrupt_nr <= watch->nr_interrupts; interrupt_nr++) 4414e98e3e1Schristos { 4424e98e3e1Schristos strcat (doc, " "); 4434e98e3e1Schristos strcat (doc, interrupt_nr_to_str (sd, interrupt_nr)); 4444e98e3e1Schristos } 4454e98e3e1Schristos int_options[0].doc_name = "watch-cycles-ACTION"; 4464e98e3e1Schristos int_options[0].arg = "[+]COUNT"; 4474e98e3e1Schristos int_options[0].doc = doc; 4484e98e3e1Schristos } 4494e98e3e1Schristos int_options[1].doc_name = "watch-pc-ACTION"; 4504e98e3e1Schristos int_options[1].arg = "[!]ADDRESS"; 4514e98e3e1Schristos int_options[1].doc = 4524e98e3e1Schristos "Watch the PC, take ACTION when matches ADDRESS (in range ADDRESS,ADDRESS), `!' negates test"; 4534e98e3e1Schristos int_options[2].doc_name = "watch-clock-ACTION"; 4544e98e3e1Schristos int_options[2].arg = "[+]MILLISECONDS"; 4554e98e3e1Schristos int_options[2].doc = 4564e98e3e1Schristos "Watch the clock, take ACTION after MILLISECONDS (`+' for every MILLISECONDS)"; 4574e98e3e1Schristos 4584e98e3e1Schristos sim_add_option_table (sd, NULL, int_options); 4594e98e3e1Schristos } 4604e98e3e1Schristos return SIM_RC_OK; 4614e98e3e1Schristos } 462