dbgLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:55k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* dbgLib.c - debugging facilities */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01y,26mar02,pai  Added code to display Streaming SIMD Registers (SPR 74103).
  8. 01x,09nov01,jhw  Revert WDB_INFO to be inside of WIND_TCB.
  9. 01w,05nov01,jn   use symFindSymbol for symbol lookup (SPR #7453)
  10. 01v,17oct01,jhw  Access WDB_INFO from WIND_TCB pointer pWdbInfo.
  11. 01u,03apr01,kab  Added _WRS_ALTIVEC_SUPPORT
  12. 01t,14mar01,pcs  Added code to display ALTIVEC Registers.
  13. 01s,08nov00,zl   added dsp show routine call.
  14. 01r,03mar00,zl   merged SH support from T1
  15. 01q,15mar99,elg  change documentation of tt() (SPR 20892).
  16. 01p,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  17. 01o,18jan99,elg  Authorize breakpoints in branch delay slot (SPR 24356).
  18. 01n,31aug98,ms   dbgTlSnglStep only conditionally prints fpp regs (SPR 9198).
  19. 01m,23apr98,dbt  code cleanup
  20. 01l,16mar98,dbt  documentation and code cleanup.
  21. 01k,19nov97,dbt  modified to merge with WDB debugger
  22. 10a,14jul97,dgp  doc: add windsh x-ref to cret() & so(), change ^C to CTRL-C
  23. 09z,21feb97,tam  moved _dbgDsmInstRtn declaration to funcBind.c
  24. 09z,28nov96,cdp  added ARM support (make things line up in dbgPrintCall).
  25. 09y,23jan96,tpr  turned off the Trace capability for the PPC403ga.
  26. 09x,06oct95,jdi  changed Debugging .pG's to .tG "Shell".
  27. 09w,31aug95,jdi  doc tweak to b(); changed <passcount> to <count> -- SPR 4603.
  28. 09v,20mar95,jdi  doc tweak to l().
  29. 09u,01feb95,jdi  added special synopsis to bh() for i386/i486.
  30. 09u,01feb95,rhp  doc: simplify integration with standard VxWorks docn by
  31.                  limiting impact of eventpoints to EVENTPOINTS para and 
  32.                  e() routine; also propagate recent doc changes to 
  33.                  standard bh() man page.
  34. ...deleted pre 95 history
  35. */
  36. /*
  37. DESCRIPTION
  38. This library contains VxWorks's primary interactive debugging routines, which 
  39. provide the following facilities:
  40.     - task breakpoints
  41.     - task single-stepping
  42.     - symbolic disassembly
  43.     - symbolic task stack tracing
  44. In addition, dbgLib provides the facilities necessary for enhanced use
  45. of other VxWorks functions, including:
  46.     - enhanced shell abort and exception handling (via tyLib and excLib)
  47. The facilities of excLib are used by dbgLib to support breakpoints,
  48. single-stepping, and additional exception handling functions.
  49. INITIALIZATION
  50. The debugging facilities provided by this module are optional.  In the
  51. standard VxWorks development configuration as distributed, the debugging
  52. package is included.  The configuration macro is INCLUDE_DEBUG.
  53. When defined, it enables the call to dbgInit() in the task usrRoot()
  54. in usrConfig.c.  The dbgInit() routine initializes dbgLib and must be made
  55. before any other routines in the module are called.
  56. BREAKPOINTS
  57. Use the routine b() or bh() to set breakpoints.  Breakpoints can be set to 
  58. be hit by a specific task or all tasks.  Multiple breakpoints for different 
  59. tasks can be set at the same address.  Clear breakpoints with bd() and bdall().
  60. When a task hits a breakpoint, the task is suspended and a message is
  61. displayed on the console.  At this point, the task can be examined,
  62. traced, deleted, its variables changed, etc.  If you examine the task at
  63. this point (using the i() routine), you will see that it is in a suspended
  64. state.  The instruction at the breakpoint address has not yet been executed.
  65. To continue executing the task, use the c() routine.  The breakpoint
  66. remains until it is explicitly removed.
  67. EVENTPOINTS (WINDVIEW)
  68. When WindView is installed, dbgLib supports eventpoints.  Use the routine
  69. e() to set eventpoints.  Eventpoints can be set to be hit by a specific
  70. task or all tasks.  Multiple eventpoints for different tasks can be set at
  71. the same address.
  72. When a task hits an eventpoint, an event is logged and is displayed by
  73. VxWorks kernel instrumentation.
  74. You can manage eventpoints with the same facilities that manage
  75. breakpoints:  for example, unbreakable tasks (discussed below) ignore
  76. eventpoints, and the b() command (without arguments) displays
  77. eventpoints as well as breakpoints.  As with breakpoints, you can clear
  78. eventpoints with bd() and bdall().
  79. UNBREAKABLE TASKS
  80. An f2unbreakablefP task ignores all breakpoints.  Tasks can be spawned
  81. unbreakable by specifying the task option VX_UNBREAKABLE.  Tasks can
  82. subsequently be set unbreakable or breakable by resetting VX_UNBREAKABLE
  83. with taskOptionsSet().  Several VxWorks tasks are spawned unbreakable,
  84. such as the shell, the exception support task excTask(), and several
  85. network-related tasks.
  86. DISASSEMBLER AND STACK TRACER
  87. The l() routine provides a symbolic disassembler.  The tt() routine
  88. provides a symbolic stack tracer.
  89. SHELL ABORT AND EXCEPTION HANDLING
  90. This package includes enhanced support for the shell in a debugging
  91. environment.  The terminal abort function, which restarts the shell, is
  92. invoked with the abort key if the OPT_ABORT option has been set.  By
  93. default, the abort key is CTRL-C.  For more information, see the manual
  94. entries for tyAbortSet() and tyAbortFuncSet().
  95. THE DEFAULT TASK AND TASK REFERENCING
  96. Many routines in this module take an optional task name or ID as an
  97. argument.  If this argument is omitted or zero, the "current" task is
  98. used.  The current task (or "default" task) is the last task referenced.
  99. The dbgLib library uses taskIdDefault() to set and get the last-referenced
  100. task ID, as do many other VxWorks routines.
  101. All VxWorks shell expressions can reference a task by either ID or name.
  102. The shell attempts to resolve a task argument to a task ID; if no match is
  103. found in the system symbol table, it searches for the argument in the list
  104. of active tasks.  When it finds a match, it substitutes the task name with
  105. its matching task ID.  In symbol lookup, symbol names take precedence over
  106. task names.
  107. INTERNAL
  108. Architecture:
  109. The VxWorks native debugger is structured to be portable across different
  110. architectures. Six files make up the debugger:  dbgLib.c, dbgTaskLib.c,
  111. wdbDbgLib.c, dbgArchLib.c, wdbDbgALib.s and wdbDbgArchLib.c. The three
  112. first files contain the architecture-independent functions, the others
  113. contains the architecture-dependent support functions.
  114. CAVEAT
  115. When a task is continued, c() and s() routines do not yet distinguish
  116. between a suspended task or a task suspended by the debugger.  Therefore, 
  117. use of these routines should be restricted to only those tasks being
  118. debugged.
  119. INCLUDE FILES: dbgLib.h
  120. SEE ALSO
  121. excLib, tyLib, taskIdDefault(), taskOptionsSet(), tyAbortSet(),
  122. tyAbortFuncSet(),
  123. .pG "Target Shell,"
  124. windsh,
  125. .tG "Shell"
  126. */
  127. /* LINTLIBRARY */
  128. #include "vxWorks.h"
  129. #include "iv.h"
  130. #include "esf.h"
  131. #include "intLib.h"
  132. #include "ioLib.h"
  133. #include "memLib.h"
  134. #include "dbgLib.h"
  135. #include "dsmLib.h"
  136. #include "regs.h"
  137. #include "shellLib.h"
  138. #include "stdio.h"
  139. #include "stdlib.h"
  140. #include "string.h"
  141. #include "trcLib.h"
  142. #include "tyLib.h"
  143. #include "usrLib.h"
  144. #include "vxLib.h"
  145. #include "private/cplusLibP.h"
  146. #include "private/windLibP.h"
  147. #include "private/taskLibP.h"
  148. #include "private/funcBindP.h"
  149. #include "private/dbgLibP.h"
  150. #include "wdb/wdbDbgLib.h"
  151. /* defines */
  152. #define DBG_INFO(p)      (&(((WIND_TCB *)(p))->wdbInfo))
  153. #define DBG_DEMANGLE_PRINT_LEN 256  /* Num chars of demangled names to print */
  154. /* error messages */
  155. #define DBG_TASK_NOT_FOUND "Task not foundn"
  156. #define DBG_ILL_BKPT_ADDR "Illegal Breakpoint Address: 0x%08xn"
  157. #define DBG_BKPT_TBL_FULL "Breakpoint table is fulln"
  158. #define DBG_ILL_EVTPT_ADDR "Illegal Eventpoint Address: 0x%08xn"
  159. #define DBG_EVTPT_TBL_FULL "Eventpoint table is fulln"
  160. #define DBG_HW_BKPT_REGS_FULL "Cannot set hardware breakpoint. All hardware breakpoint registers are in usen"
  161. #define DBG_INV_HW_BKPT_TYPE "Invalid hardware breakpoint typen"
  162. #define DBG_NO_BKPT_AT_ADDR "No breakpoint at 0x%08x"
  163. #define DBG_TASK_IX_NOT_FOUND "Task %#x not foundn"
  164. #define DBG_CRET_NOT_SUPP "cret not supportedn"
  165. #define DBG_NO_BKPTS "No breakpointsn"
  166. /* typedefs */
  167. typedef struct                  /* EVT_CALL_ARGS */
  168.     {
  169.     FUNCPTR evtRtn; /* event routine */
  170.     int  evtRtnArg; /* event routine argument */
  171.     event_t eventId; /* event ID */
  172.     } EVT_CALL_ARGS;
  173. /* globals */
  174. BOOL dbgPrintFpp;
  175. BOOL dbgPrintDsp;
  176. #ifdef _WRS_ALTIVEC_SUPPORT
  177. BOOL            dbgPrintAltivec;
  178. #endif /* _WRS_ALTIVEC_SUPPORT */
  179. BOOL            dbgPrintSimd;
  180. /* extern */
  181. IMPORT FUNCPTR _func_breakpoint;
  182. IMPORT FUNCPTR _func_trace;
  183. IMPORT FUNCPTR _func_trap;
  184. IMPORT FUNCPTR _func_dbgTargetNotify;
  185. IMPORT BOOL dbgUnbreakableOld;
  186. /* locals */
  187. static INSTR * nextToDsm = NULL; /* instruction to disassemble from */
  188. static int dfltCount = 10; /* # of instructions to disassemble */
  189. /* forward declarations */
  190. LOCAL void  dbgTargetNotify (UINT32 flag, UINT32 addr, 
  191.     REG_SET * pRegisters);
  192. LOCAL BRKPT * dbgBrkAdd (INSTR * addr, int task, unsigned flags, 
  193.     unsigned action, unsigned count, 
  194.     FUNCPTR callRtn, int callArg);
  195. LOCAL STATUS dbgCheckBreakable (int task);
  196. LOCAL void dbgTlSnglStep (int task);
  197. LOCAL STATUS dbgInstall (void);
  198. LOCAL void dbgTyAbort (void);
  199. LOCAL void dbgTlTyAbort (void);
  200. LOCAL void  dbgBrkDisplay (void);
  201. LOCAL void dbgPrintAdrs (int address);
  202. LOCAL INSTR *  dbgList (INSTR * addr, int count);
  203. LOCAL void  dbgBrkPrint (INSTR * addr);
  204. LOCAL void dbgE (EVT_CALL_ARGS * pEvtCall, REG_SET * pRegisters);
  205. /*******************************************************************************
  206. *
  207. * dbgHelp - display debugging help menu
  208. *
  209. * This routine displays a summary of dbgLib utilities with a
  210. * short description of each, similar to the following:
  211. *
  212. * .CS
  213. *     dbgHelp                         Print this list
  214. *     dbgInit                         Install debug facilities
  215. *     b                               Display breakpoints
  216. *     b         addr[,task[,count]]   Set breakpoint
  217. *     e         addr[,eventNo[,task[,func[,arg]]]]] Set eventpoint (WindView)
  218. *     bd        addr[,task]           Delete breakpoint
  219. *     bdall     [task]                Delete all breakpoints
  220. *     c         [task[,addr[,addr1]]] Continue from breakpoint
  221. *     cret      [task]                Continue to subroutine return
  222. *     s         [task[,addr[,addr1]]] Single step
  223. *     so        [task]                Single step/step over subroutine
  224. *     l         [adr[,nInst]]         List disassembled memory
  225. *     tt        [task]                Do stack trace on task
  226. *     bh        addr[,access[,task[,count[,quiet]]]] set hardware breakpoint
  227. *                                     (if supported by the architecture)
  228. * .CE
  229. *
  230. * RETURNS: N/A
  231. *
  232. * SEE ALSO:
  233. * .pG "Target Shell"
  234. */
  235. void dbgHelp (void)
  236.     {
  237.     static char * help_msg  = "n
  238. dbgHelp                         Print this listn
  239. dbgInit                         Install debug facilitiesn
  240. b                               Display breakpoints and eventpointsn
  241. b         addr[,task[,count]]   Set breakpointn
  242. e         addr[,eventNo[,task[,func[,arg]]]]] Set eventpointn
  243. bd        addr[,task]           Delete breakpointn
  244. bdall     [task]                Delete all breakpoints and eventpointsn
  245. c         [task[,addr[,addr1]]] Continue from breakpointn
  246. cret      [task]                Continue to subroutine returnn
  247. s         [task[,addr[,addr1]]] Single stepn
  248. so        [task]                Single step/step over subroutinen
  249. l         [adr[,nInst]]         List disassembled memoryn
  250. tt        [task]                Do stack trace on taskn";
  251.     printf ("%s", help_msg);
  252.     printf ("%s", _archHelp_msg);
  253.     }
  254. /*******************************************************************************
  255. *
  256. * dbgInit - initialize the local debugging package
  257. *
  258. * This routine initializes the local debugging package and enables the basic
  259. * breakpoint and single-step functions.
  260. *
  261. * This routine also enables the shell abort function, CTRL-C.
  262. *
  263. * NOTE
  264. * The debugging package should be initialized before any debugging routines
  265. * are used.  If the configuration macro INCLUDE_DEBUG is defined, dbgInit()
  266. * is called by the root task, usrRoot(), in usrConfig.c.
  267. *
  268. * RETURNS: OK, always.
  269. *
  270. * SEE ALSO:
  271. * .pG "Target Shell"
  272. */
  273. STATUS dbgInit (void)
  274.     {
  275.     _dbgArchInit (); /* initialise disassembler ... */
  276.     tyAbortFuncSet ((FUNCPTR) dbgTyAbort); /* set abort routine */
  277.     _func_bdall = bdall;
  278.     return (OK);
  279.     }
  280. /*******************************************************************************
  281. *
  282. * dbgInstall - install the debugging facility
  283. *
  284. * This routine installs the debug package.
  285. * It performs the following actions:
  286. *
  287. *   - Initialize breakpoint entry lists
  288. *
  289. *   - Sets the interrupt vectors of the breakpoint
  290. *     and trace hardware interrupts to the appropriate
  291. *     debug interrupt handlers.
  292. *
  293. *   - Adds the debug task switch routine to the kernel
  294. *     context switch call out.
  295. *
  296. * This routine is called automatically by all breakpoint related routines
  297. * in this library.  Note that dbgInstall should not be called until
  298. * the following items have been initialized:
  299. *
  300. *   - the pipe driver
  301. *   - the ty driver used for logging
  302. *   - the exception handler library (excLib)
  303. *   - the message logging library (logLib)
  304. *
  305. * RETURNS: OK, or ERROR if unable to install task switch routine.
  306. *
  307. * NOMANUAL
  308. */
  309. LOCAL STATUS dbgInstall (void)
  310.     {
  311.     static BOOL dbgInstalled = FALSE;    /* TRUE = facility installed */
  312.     /* if debugging facility is not already installed, then install it
  313.      * by initializing lists and installing switch hook.
  314.      */
  315.     if (!dbgInstalled)
  316. {
  317. /* initialize breakpoint lists */
  318. wdbDbgBpListInit ();
  319. /* connect various handlers */
  320. dbgTaskBpHooksInstall ();
  321. /* routine to be called when a breakpoint is encountered */
  322. _func_dbgTargetNotify = (FUNCPTR) dbgTargetNotify;
  323. #if DBG_NO_SINGLE_STEP
  324. /* 
  325.  * If _func_trap was not already initialized by the WDB agent, 
  326.  * initialize it.
  327.  */
  328. if (_func_trap == NULL)
  329.     _func_trap = (FUNCPTR) dbgTaskBpTrap;
  330. #else /* DBG_NO_SINGLE_STEP */ 
  331. /*
  332.  * If _func_trace was not already initialized by the WDB agent,
  333.  * initialize it.
  334.  */
  335. if (_func_trace == NULL)
  336.     _func_trace = (FUNCPTR) dbgTaskBpTrace;
  337. /* 
  338.  * if _func_breakpoint was not already initialized by the WDB agent, 
  339.  * initialize it. 
  340.  */
  341. if (_func_breakpoint == NULL)
  342.     _func_breakpoint = (FUNCPTR) dbgTaskBpBreakpoint;
  343. #endif /* DBG_NO_SINGLE_STEP */
  344. /* Insert the break and trace vectors, set breakpoint instruction */
  345. wdbDbgArchInit ();
  346. dbgInstalled = TRUE;
  347. }
  348.     return (OK);
  349.     }
  350. /*******************************************************************************
  351. *
  352. * b - set or display breakpoints
  353. *
  354. * This routine sets or displays breakpoints.  To display the list of
  355. * currently active breakpoints, call b() without arguments:
  356. * .CS
  357. *     -> b
  358. * .CE
  359. * The list shows the address, task, and pass count of each breakpoint.
  360. * Temporary breakpoints inserted by so() and cret() are also indicated.
  361. *
  362. * To set a breakpoint with b(), include the address, which can be
  363. * specified numerically or symbolically with an optional offset.
  364. * The other arguments are optional:
  365. * .CS
  366. *     -> b addr[,task[,count[,quiet]]]
  367. * .CE
  368. * If <task> is zero or omitted, the breakpoint will apply to all breakable
  369. * tasks.  If <count> is zero or omitted, the breakpoint will occur every
  370. * time it is hit.  If <count> is specified, the break will not occur
  371. * until the <count> +1th time an eligible task hits the breakpoint
  372. * (i.e., the breakpoint is ignored the first <count> times it is hit).
  373. *
  374. * If <quiet> is specified, debugging information destined for the console
  375. * will be suppressed when the breakpoint is hit.  This option is included
  376. * for use by external source code debuggers that handle the breakpoint
  377. * user interface themselves.
  378. *
  379. * Individual tasks can be unbreakable, in which case breakpoints that
  380. * otherwise would apply to a task are ignored.  Tasks can be spawned
  381. * unbreakable by specifying the task option VX_UNBREAKABLE.
  382. * Tasks can also be set unbreakable or breakable by resetting
  383. * VX_UNBREAKABLE with the routine taskOptionsSet().
  384. *
  385. * RETURNS
  386. * OK, or ERROR if <addr> is illegal or the breakpoint table is full.
  387. *
  388. * SEE ALSO: bd(), taskOptionsSet(),
  389. * .pG "Target Shell,"
  390. * windsh,
  391. * .tG "Shell"
  392. */
  393. STATUS b
  394.     (
  395.     INSTR * addr, /* where to set breakpoint, or  */
  396. /* 0 = display all breakpoints  */
  397.     int   task, /* task for which to set breakboint,   */
  398. /* 0 = set all tasks    */
  399.     int count, /* number of passes before hit  */
  400.     BOOL quiet /* TRUE = don't print debugging info,  */
  401. /* FALSE = print debugging info */
  402.     )
  403.     {
  404.     int tid = 0; /* task ID */
  405.     int val; /* temporary buffer */
  406.     int action; /* breakpoint action */
  407.     int  retVal = OK; /* return value */
  408.     if (dbgInstall () != OK)
  409. return (ERROR);
  410.     if (task != 0)
  411. tid = taskIdFigure (task); /* convert to task id */
  412.     if (tid == ERROR)
  413. {
  414. printErr (DBG_TASK_NOT_FOUND);
  415. return (ERROR);
  416. }
  417.     /* NULL address means show all breakpoints */
  418.     if (addr == NULL) 
  419. {
  420. dbgBrkDisplay ();
  421. return (OK);
  422. }
  423.     /* if text segment protection turned on, first write enable the page */
  424.     TEXT_UNLOCK(addr);
  425.     /* check validity of breakpoint address */
  426.     if (!ALIGNED ((int) addr, DBG_INST_ALIGN) ||
  427. (vxMemProbe ((char *)addr, VX_READ,
  428. sizeof(INSTR), (char *)&val) != OK) ||
  429. (vxMemProbe ((char *)addr, VX_WRITE,
  430. sizeof(INSTR), (char *)&val) != OK))
  431. {
  432. printErr (DBG_ILL_BKPT_ADDR, (int)addr);
  433. retVal = ERROR;
  434. goto done;
  435. }
  436.     if (quiet)
  437. action = WDB_ACTION_STOP;
  438.     else
  439. action = WDB_ACTION_STOP | WDB_ACTION_NOTIFY;
  440.     /* add new breakpoint */
  441.     if (dbgBrkAdd (addr, tid, 0, action, count, NULL, 0) == NULL)
  442. {
  443. printErr (DBG_BKPT_TBL_FULL);
  444. retVal = ERROR;
  445. goto done;
  446. }
  447. done:
  448.     TEXT_LOCK(addr);
  449.     return (retVal);
  450.     }
  451. /******************************************************************************
  452. *
  453. * e - set or display eventpoints (WindView)
  454. *
  455. * This routine sets "eventpoints"--that is, breakpoint-like instrumentation
  456. * markers that can be inserted in code to generate and log an event for use
  457. * with WindView.  Event logging must be enabled with wvEvtLogEnable() for
  458. * the eventpoint to be logged.
  459. *
  460. * <eventId> selects the evenpoint number that will be logged: it is in 
  461. * the user event ID range (0-25536).
  462. *
  463. * If <addr> is NULL, then all eventpoints and breakpoints are displayed.
  464. * If <taskNameOrId> is 0, then this event is logged in all tasks.
  465. * The <evtRtn> routine is called when this eventpoint is hit.  If <evtRtn>
  466. * returns OK, then the eventpoint is logged; otherwise, it is ignored.
  467. * If <evtRtn> is a NULL pointer, then the eventpoint is always logged.
  468. *
  469. * Eventpoints are exactly like breakpoints (which are set with the b()
  470. * command) except in how the system responds when the eventpoint is hit.  An
  471. * eventpoint typically records an event and continues immediately (if
  472. * <evtRtn> is supplied, this behavior may be different).  Eventpoints cannot
  473. * be used at interrupt level.
  474. *
  475. * To delete an eventpoint, use bd().
  476. *
  477. * RETURNS
  478. * OK, or ERROR if <addr> is odd or nonexistent in memory, or if the
  479. * breakpoint table is full.
  480. *
  481. * SEE ALSO: wvEvent()
  482. */
  483. STATUS e
  484.     (
  485.     INSTR * addr, /* where to set eventpoint, or */
  486. /* 0 means display all eventpoints */
  487.     event_t eventId, /* event ID */
  488.     int taskNameOrId, /* task affected; 0 means all tasks */
  489.     FUNCPTR evtRtn, /* function to be invoked; */
  490. /* NULL means no function is invoked */
  491.     int arg /* argument to be passed to <evtRtn> */
  492.     )
  493.     {
  494.     int tid = 0; /* task ID */
  495.     int val; /* temporary buffer */
  496.     int  retVal = OK; /* return value */
  497.     EVT_CALL_ARGS *  pEvtCall; /* structure to pass arguments */
  498.     if (dbgInstall () != OK)
  499. return (ERROR);
  500.     if (taskNameOrId != 0)
  501. tid = taskIdFigure (taskNameOrId); /* convert to task id */
  502.     if (tid == ERROR)
  503. {
  504. printErr (DBG_TASK_NOT_FOUND);
  505. return (ERROR);
  506. }
  507.     /* NULL address means show all breakpoints */
  508.     if (addr == NULL) 
  509. {
  510. dbgBrkDisplay ();
  511. return (OK);
  512. }
  513.     /* if text segment protection turned on, first write enable the page */
  514.     TEXT_UNLOCK(addr);
  515.     /* check validity of breakpoint address */
  516.     if (!ALIGNED ((int) addr, DBG_INST_ALIGN) ||
  517. (vxMemProbe ((char *)addr, VX_READ,
  518. sizeof(INSTR), (char *)&val) != OK) ||
  519. (vxMemProbe ((char *)addr, VX_WRITE,
  520. sizeof(INSTR), (char *)&val) != OK))
  521. {
  522. printErr (DBG_ILL_EVTPT_ADDR, (int)addr);
  523. retVal = ERROR;
  524. goto done;
  525. }
  526.     /*
  527.      * The runtime callout, dbgE, requires three parameters (an event number,
  528.      * and a conditioning routine and argument). However the breakpoints
  529.      * only support passing one argument to the callout. So here we allocate
  530.      * a structure and pass it's address to the callout.
  531.      * XXX - this creates a memory leak of 12 bytes.
  532.      * We need to store the address of the structure with the eventpoint,
  533.      * and have the breakpoint delete routines check and free the memory.
  534.      */
  535.     if ((pEvtCall = (EVT_CALL_ARGS *) malloc (sizeof (EVT_CALL_ARGS))) == NULL)
  536. {
  537. retVal = ERROR;
  538. goto done;
  539. }
  540.     pEvtCall->evtRtn = evtRtn;
  541.     pEvtCall->evtRtnArg = arg;
  542.     pEvtCall->eventId = eventId;
  543.     /* add new breakpoint */
  544.     if (dbgBrkAdd (addr, tid, BP_EVENT, WDB_ACTION_CALL, 0, (FUNCPTR) dbgE, 
  545. (int) pEvtCall) == NULL)
  546. {
  547. printErr (DBG_EVTPT_TBL_FULL);
  548. retVal = ERROR;
  549. goto done;
  550. }
  551. done:
  552.     TEXT_LOCK(addr);
  553.     return (retVal);
  554.     }
  555. #if DBG_HARDWARE_BP
  556. /******************************************************************************
  557. *
  558. * bh - set a hardware breakpoint
  559. *
  560. * This routine is used to set a hardware breakpoint.   If the architecture
  561. * allows it, this function will add the breakpoint to the list of breakpoints
  562. * and set the hardware breakpoint register(s).  For more information, see the
  563. * manual entry for b().
  564. *
  565. * NOTE
  566. * The types of hardware breakpoints vary with the architectures.  Generally,
  567. * a hardware breakpoint can be a data breakpoint or an instruction breakpoint.
  568. *
  569. * RETURNS
  570. * OK, or ERROR if <addr> is illegal or the hardware breakpoint table is
  571. * full.
  572. *
  573. * SEE ALSO: b(),
  574. * .pG "Target Shell"
  575. */
  576. STATUS bh
  577.     (
  578.     INSTR * addr, /* where to set breakpoint, or */
  579. /* 0 = display all breakpoints */
  580.     int access, /* access type (arch dependant) */
  581.     int task, /* task for which to set breakboint, */
  582. /* 0 = set all tasks */
  583.     int count, /* number of passes before hit */
  584.     BOOL quiet /* TRUE = don't print debugging info,  */
  585. /* FALSE = print debugging info */
  586.     )
  587.     {
  588.     int tid = 0;
  589.     BRKPT * pBp;
  590.     DBG_REGS dbgRegs;
  591.     dll_t * pDll;
  592.     int action;
  593.     int status;
  594.     if (dbgInstall () != OK)
  595. return (ERROR);
  596.     if (task != 0)
  597. tid = taskIdFigure (task); /* convert to task id */
  598.     if (tid == ERROR)
  599. {
  600. printErr (DBG_TASK_NOT_FOUND);
  601. return (ERROR);
  602. }
  603.     /* 0 address means show all breakpoints */
  604.     if (addr == NULL) 
  605. {
  606. dbgBrkDisplay ();
  607. return (OK);
  608. }
  609.     /* check validity of hardware breakpoint address */
  610.     if (wdbDbgHwAddrCheck ((UINT32) addr, access, (FUNCPTR) vxMemProbe) != OK)
  611. {
  612. printErr (DBG_ILL_BKPT_ADDR, (int)addr);
  613. return (ERROR);
  614. }
  615.     /* clean dbgRegs structure */
  616.     memset (&dbgRegs, 0, sizeof (DBG_REGS));
  617.     /* fill dbgRegs structure */
  618.    
  619.     taskLock (); /* LOCK PREEMPTION */
  620.     for (pDll = dll_head(&bpList); pDll != dll_end(&bpList);
  621. pDll = dll_next(pDll))
  622. {
  623. pBp = BP_BASE(pDll);
  624. /* check if found breakpoint is applicable to current task */
  625. if ((pBp->bp_task == ALL) || (task == ALL) || (pBp->bp_task == task))
  626.     {
  627.     if (pBp->bp_flags & BRK_HARDWARE)
  628. {
  629. if (wdbDbgHwBpSet (&dbgRegs, pBp->bp_flags & BRK_HARDMASK, 
  630. (UINT32) pBp->bp_addr) != OK)
  631.     {
  632.     printErr (DBG_HW_BKPT_REGS_FULL);
  633.     taskUnlock (); /* UNLOCK PREEMPTION */
  634.     return (ERROR);
  635.     }
  636. }
  637.     }
  638. }
  639.     taskUnlock (); /* UNLOCK PREEMPTION */
  640.     if (quiet)
  641. action = WDB_ACTION_STOP;
  642.     else
  643. action = WDB_ACTION_STOP | WDB_ACTION_NOTIFY;
  644.     status = wdbDbgHwBpSet (&dbgRegs, access, (UINT32) addr);
  645.     switch (status)
  646. {
  647. case WDB_ERR_HW_REGS_EXHAUSTED:
  648.     printErr (DBG_HW_BKPT_REGS_FULL);
  649.     return (ERROR);
  650. case WDB_ERR_INVALID_HW_BP:
  651.     printErr (DBG_INV_HW_BKPT_TYPE);
  652.     return (ERROR);
  653. case OK:
  654.     break;
  655. default:
  656.     return (ERROR);
  657. }
  658.     /* add breakpoint to breakpoint table */
  659.     if ((pBp = dbgBrkAdd (addr, tid, access | BRK_HARDWARE, action, 
  660. count, NULL, 0)) == NULL)
  661. {
  662. printErr (DBG_BKPT_TBL_FULL);
  663. return (ERROR);
  664. }
  665.     return (OK);
  666.     }
  667. #endif /* DBG_HARDWARE_BP */
  668. /*******************************************************************************
  669. *
  670. * bd - delete a breakpoint
  671. *
  672. * This routine deletes a specified breakpoint.
  673. *
  674. * To execute, enter:
  675. * .CS
  676. *     -> bd addr [,task]
  677. * .CE
  678. * If <task> is omitted or zero, the breakpoint will be removed for all tasks.
  679. * If the breakpoint applies to all tasks, removing it for only a single
  680. * task will be ineffective.  It must be removed for all tasks and then set
  681. * for just those tasks desired.  Temporary breakpoints inserted by the
  682. * routines so() or cret() can also be deleted.
  683. *
  684. * RETURNS
  685. * OK, or ERROR if there is no breakpoint at the specified address.
  686. *
  687. * SEE ALSO: b(),
  688. * .pG "Target Shell,"
  689. * windsh,
  690. * .tG "Shell"
  691. */
  692. STATUS bd
  693.     (
  694.     INSTR * addr, /* address of breakpoint to delete      */
  695.     int task /* task for which to delete breakpoint, */
  696. /* 0 = delete for all tasks      */
  697.     )
  698.     {
  699.     BRKPT * pBp;
  700.     int  tid = 0;
  701.     dll_t * pDll;
  702.     dll_t * pDllNext;
  703.     if (dbgInstall () != OK)
  704. return (ERROR);
  705.     if (task != 0)
  706. tid = taskIdFigure (task); /* convert to task id */
  707.     if (tid == ERROR)
  708. {
  709. printErr (DBG_TASK_NOT_FOUND);
  710. return (ERROR);
  711. }
  712.     /* search breakpoint table for entry with correct address & task */
  713.     taskLock (); /* LOCK PREEMPTION */
  714.     for (pDll = dll_head(&bpList); pDll != dll_end(&bpList); pDll = pDllNext)
  715. {
  716. pDllNext = dll_next(pDll);
  717. pBp = BP_BASE(pDll);
  718. if (pBp->bp_addr == addr && 
  719. (pBp->bp_task == tid || tid == ALL) &&
  720. !(pBp->bp_flags & BP_HOST))
  721.     {
  722.     wdbDbgBpRemove (pBp);
  723.     taskUnlock (); /* UNLOCK PREEMPTION */
  724.     return (OK);
  725.     }
  726. }
  727.     taskUnlock (); /* UNLOCK PREEMPTION */
  728.     /*
  729.      * print an error message if we have not found the breakpoint to remove
  730.      */
  731.     printErr (DBG_NO_BKPT_AT_ADDR, (int) addr);
  732.     if (tid == ALL)
  733. printErr ("n");
  734.     else
  735. printErr (" for task %#x (%s)n", tid, taskName (tid));
  736.     return (ERROR);
  737.     }
  738. /*******************************************************************************
  739. *
  740. * bdall - delete all breakpoints
  741. *
  742. * This routine removes all breakpoints.
  743. *
  744. * To execute, enter:
  745. * .CS
  746. *     -> bdall [task]
  747. * .CE
  748. * If <task> is specified, all breakpoints that apply to that task are
  749. * removed.  If <task> is omitted,  all breakpoints for all tasks are
  750. * removed.  Temporary breakpoints inserted by so() or cret() are not
  751. * deleted; use bd() instead.
  752. *
  753. * RETURNS: OK, always.
  754. *
  755. * SEE ALSO: bd(),
  756. * .pG "Target Shell,"
  757. * windsh,
  758. * .tG "Shell"
  759. */
  760. STATUS bdall
  761.     (
  762.     int task /* task for which to delete breakpoints, */
  763. /* 0 = delete for all tasks       */
  764.     )
  765.     {
  766.     int  tid = 0;
  767.     dll_t * pDll;
  768.     dll_t * pDllNext;
  769.     BRKPT * pBp;
  770.     if (dbgInstall () != OK)
  771. return (ERROR);
  772.     if (task != 0)
  773. tid = taskIdFigure (task); /* convert to task id */
  774.     if (tid == ERROR)
  775. {
  776. printErr (DBG_TASK_NOT_FOUND);
  777. return (ERROR);
  778. }
  779.     taskLock (); /* LOCK PREEMPTION */
  780.     for (pDll = dll_head(&bpList); pDll != dll_end(&bpList); pDll = pDllNext)
  781. {
  782. pDllNext = dll_next(pDll);
  783. pBp = BP_BASE(pDll);
  784. /* we can't remove a breakpoint set by a host tool */
  785. if ((pBp->bp_task == tid || tid == ALL) && !(pBp->bp_flags & BP_HOST))
  786.     wdbDbgBpRemove (pBp);
  787. }
  788.     taskUnlock (); /* UNLOCK PREEMPTION */
  789.     return (OK);
  790.     }
  791. /*******************************************************************************
  792. *
  793. * c - continue from a breakpoint
  794. *
  795. * This routine continues the execution of a task that has stopped at a
  796. * breakpoint.  
  797. *
  798. * To execute, enter:
  799. * .CS
  800. *     -> c [task [,addr[,addr1]]]
  801. * .CE
  802. * If <task> is omitted or zero, the last task referenced is assumed.
  803. * If <addr> is non-zero, the program counter is changed to <addr>;
  804. * if <addr1> is non-zero, the next program counter is changed to <addr1>,
  805. * and the task is continued.
  806. *
  807. * CAVEAT
  808. * When a task is continued, c() does not distinguish between a suspended
  809. * task or a task suspended by the debugger.  Therefore, its use should be
  810. * restricted to only those tasks being debugged.
  811. * NOTE
  812. * The next program counter, <addr1>, is currently supported only by SPARC.
  813. *
  814. * RETURNS:
  815. * OK, or ERROR if the specified task does not exist.
  816. *
  817. * SEE ALSO: tr(),
  818. * .pG "Target Shell,"
  819. * windsh,
  820. * .tG "Shell"
  821. */
  822. STATUS c
  823.     (
  824.     int task, /* task that should proceed from breakpoint     */
  825.     INSTR * addr, /* address to continue at; 0 = next instruction */
  826.     INSTR * addr1 /* address for npc; 0 = instruction next to pc */
  827.     )
  828.     {
  829.     int  tid = 0;
  830.     WIND_TCB * pTcb;
  831.     if (dbgInstall () != OK)
  832. return (ERROR);
  833.     if ((tid = taskIdFigure (task)) == ERROR)   /* convert to task id */
  834. {
  835. printErr (DBG_TASK_NOT_FOUND);
  836. return (ERROR);
  837. }
  838.     tid = taskIdDefault (tid); /* set default task id */
  839.     if (dbgCheckBreakable (tid) == ERROR)
  840. return (ERROR);
  841.     pTcb = taskTcb(tid);
  842.     if (pTcb == NULL)
  843. return (ERROR);
  844.     if (!taskIsSuspended (tid))
  845. return (ERROR);
  846.     /* adjust pc & continue the task */
  847.     if (addr != 0)
  848. _dbgTaskPCSet (tid, addr, addr1);
  849.     if (dbgTaskCont (tid) != OK)
  850. {
  851. printErr (DBG_TASK_IX_NOT_FOUND, tid);
  852. return (ERROR);
  853. }
  854.     return (OK);
  855.     }
  856. /*******************************************************************************
  857. *
  858. * cret - continue until the current subroutine returns
  859. *
  860. * This routine places a breakpoint at the return address of the current
  861. * subroutine of a specified task, then continues execution of that task.
  862. *
  863. * To execute, enter:
  864. * .CS
  865. *     -> cret [task]
  866. * .CE
  867. * If <task> is omitted or zero, the last task referenced is assumed.
  868. *
  869. * When the breakpoint is hit, information about the task will be printed in
  870. * the same format as in single-stepping.  The breakpoint is automatically
  871. * removed when hit, or if the task hits another breakpoint first.
  872. *
  873. * RETURNS:
  874. * OK, or ERROR if there is no such task or the breakpoint table is
  875. * full.
  876. *
  877. * SEE ALSO: so(),
  878. * .pG "Target Shell",
  879. * windsh,
  880. * .tG "Shell"
  881. */
  882. STATUS cret
  883.     (
  884.     int task /* task to continue, 0 = default */
  885.     )
  886.     {
  887. #if  (DBG_CRET == TRUE)
  888.     int  tid = 0; /* task ID */
  889.     REG_SET regSet; /* task's register set */
  890.     WIND_TCB * pTcb; /* pointer on task TCB */
  891.     INSTR * retAdrs; /* return address */
  892.     if (dbgInstall () != OK)
  893. return (ERROR);
  894.     if ((tid = taskIdFigure (task)) == ERROR) /* convert to task id */
  895. {
  896. printErr (DBG_TASK_NOT_FOUND);
  897. return (ERROR);
  898. }
  899.     tid = taskIdDefault (tid);   /* set default task id */
  900.     /* check if task is breakable */
  901.     if (dbgCheckBreakable (tid) == ERROR)
  902. return (ERROR);
  903.     if (taskRegsGet (tid, &regSet) != OK)
  904. {
  905. printErr (DBG_TASK_IX_NOT_FOUND, tid);
  906. return (ERROR);
  907. }
  908.     pTcb = taskTcb (tid);
  909.     if (pTcb == NULL)
  910. return (ERROR);
  911.     if (!taskIsSuspended (tid))
  912. return (ERROR);
  913.     retAdrs = _dbgRetAdrsGet (&regSet);
  914.     /* add breakpoint to breakpoint table */
  915.     if (dbgBrkAdd (retAdrs, tid, BP_SO, WDB_ACTION_STOP | WDB_ACTION_NOTIFY, 
  916. 0, NULL, 0) == NULL)
  917. {
  918. printErr (DBG_BKPT_TBL_FULL);
  919. return (ERROR);
  920. }
  921.     if (dbgTaskCont (tid) != OK)
  922. {
  923. printErr (DBG_TASK_IX_NOT_FOUND, tid);
  924. return (ERROR);
  925. }
  926.     return (OK);
  927. #else /* (DBG_CRET == FALSE) */
  928.     printErr (DBG_CRET_NOT_SUPP);
  929.     return (ERROR);
  930. #endif /* (DBG_CRET == TRUE) */
  931.     }
  932. /*******************************************************************************
  933. *
  934. * s - single-step a task
  935. *
  936. * This routine single-steps a task that is stopped at a breakpoint.  
  937. *
  938. * To execute, enter:
  939. * .CS
  940. *     -> s [task[,addr[,addr1]]]
  941. * .CE
  942. * If <task> is omitted or zero, the last task referenced is assumed.
  943. * If <addr> is non-zero, then the program counter is changed to <addr>;
  944. * if <addr1> is non-zero, the next program counter is changed to <addr1>,
  945. * and the task is stepped.
  946. *
  947. * CAVEAT
  948. * When a task is continued, s() does not distinguish between a suspended
  949. * task or a task suspended by the debugger.  Therefore, its use should be
  950. * restricted to only those tasks being debugged.
  951. *
  952. * NOTE
  953. * The next program counter, <addr1>, is currently supported only by SPARC.
  954. *
  955. * RETURNS: OK, or ERROR if the debugging package is not installed, the task
  956. * cannot be found, or the task is not suspended.
  957. *
  958. * SEE ALSO:
  959. * .pG "Target Shell,"
  960. * windsh,
  961. * .tG "Shell"
  962. */
  963. STATUS s
  964.     (
  965.     int taskNameOrId, /* task to step; 0 = use default     */
  966.     INSTR * addr, /* address to step to; 0 = next instruction */
  967.     INSTR * addr1 /* address for npc, 0 = next instruction */
  968.     )
  969.     {
  970.     int tid;
  971.     WIND_TCB *  pTcb;
  972.     if (dbgInstall () != OK)
  973. return (ERROR);
  974.     if ((tid = taskIdFigure (taskNameOrId)) == ERROR)   /* convert to task id */
  975. {
  976. printErr (DBG_TASK_NOT_FOUND);
  977. return (ERROR);
  978. }
  979.     tid = taskIdDefault (tid); /* set default task id */
  980.     if (dbgCheckBreakable (tid) == ERROR)
  981. return (ERROR);
  982.     pTcb = taskTcb (tid);
  983.     if (pTcb == NULL)
  984. return (ERROR);
  985.     if (!taskIsSuspended (tid))
  986. return (ERROR);
  987.     /* adjust pc & resume the task */
  988.     if (addr != 0)
  989. _dbgTaskPCSet (tid, addr, addr1);
  990.     /* mark task as single-stepping */
  991.     DBG_INFO(tid)->wdbState |= WDB_STEP_TARGET;
  992.     if (taskResume (tid) != OK)
  993. return (ERROR);
  994.     return (OK);
  995.     }
  996. /*******************************************************************************
  997. *
  998. * so - single-step, but step over a subroutine
  999. *
  1000. * This routine single-steps a task that is stopped at a breakpoint.
  1001. * However, if the next instruction is a JSR or BSR, so() breaks at the
  1002. * instruction following the subroutine call instead.
  1003. *
  1004. * To execute, enter:
  1005. * .CS
  1006. *     -> so [task]
  1007. * .CE
  1008. * If <task> is omitted or zero, the last task referenced is assumed.
  1009. *
  1010. * SEE ALSO:
  1011. * .pG "Target Shell",
  1012. * windsh,
  1013. * .tG "Shell"
  1014. */
  1015. STATUS so
  1016.     (
  1017.     int task /* task to step; 0 = use default */
  1018.     )
  1019.     {
  1020.     INSTR * pc;
  1021.     int tid;
  1022.     WIND_TCB * pTcb;
  1023.     if (dbgInstall () != OK)
  1024. return (ERROR);
  1025.     if ((tid = taskIdFigure (task)) == ERROR)    /* convert to task id */
  1026. {
  1027. printErr (DBG_TASK_NOT_FOUND);
  1028. return (ERROR);
  1029. }
  1030.     tid = taskIdDefault (tid); /* set default task id */
  1031.     if (dbgCheckBreakable (tid) == ERROR)
  1032. return (ERROR);
  1033.     pTcb = taskTcb (tid);
  1034.     if (pTcb == NULL)
  1035. return (ERROR);
  1036.     if (!taskIsSuspended (tid))
  1037. return (ERROR);
  1038.     pc = _dbgTaskPCGet (tid);
  1039.     if (_dbgFuncCallCheck (pc))  /* check if function call instruction */
  1040. {
  1041. /* add breakpoint to breakpoint table */
  1042. if (dbgBrkAdd (pc + _dbgInstSizeGet (pc), tid, BP_SO, 
  1043. WDB_ACTION_STOP | WDB_ACTION_NOTIFY, 
  1044. 0, NULL, 0) == NULL)
  1045.     {
  1046.     printErr (DBG_BKPT_TBL_FULL);
  1047.     return (ERROR);
  1048.     }
  1049. if (dbgTaskCont (tid) == ERROR)
  1050.     {
  1051.     printErr (DBG_TASK_IX_NOT_FOUND, tid);
  1052.     return (ERROR);
  1053.     }
  1054. }
  1055.     else
  1056. {
  1057. /* mark task as single-stepping */
  1058. DBG_INFO(tid)->wdbState |= WDB_STEP_TARGET;
  1059. /* resume the task */
  1060. if (taskResume (tid) != OK)
  1061.     {
  1062.     printErr (DBG_TASK_IX_NOT_FOUND, tid);
  1063.     return (ERROR);
  1064.     }
  1065. }
  1066.     return (OK);
  1067.     }
  1068. /*******************************************************************************
  1069. *
  1070. * dbgBrkAdd - add a breakpoint to the breakpoint table
  1071. *
  1072. * RETURNS: 
  1073. * Breakpoint structure address or NULL if we can't add the breakpoint.
  1074. *
  1075. * NOMANUAL
  1076. */
  1077. LOCAL BRKPT * dbgBrkAdd
  1078.     (
  1079.     INSTR * addr, /* where to set breakpoint */
  1080.     int task, /* task for which to set breakboint */
  1081.     unsigned flags, /* breakpoint flags */
  1082.     unsigned    action, /* breakpoint action */
  1083.     unsigned    count, /* breakpoint count */
  1084.     FUNCPTR callRtn, /* routine to call */
  1085.     int callArg /* routine argument */
  1086.     )
  1087.     {
  1088.     BRKPT * pBp;
  1089.     /* get a free breakpoint entry */
  1090.     taskLock (); /* LOCK PREEMPTION */
  1091.     if (dll_empty (&bpFreeList))
  1092. pBp = NULL;
  1093.     else
  1094. {
  1095. pBp = BP_BASE(dll_tail (&bpFreeList));
  1096. dll_remove (&pBp->bp_chain);
  1097. }
  1098.     taskUnlock (); /* UNLOCK PREEMPTION */
  1099.     if (pBp == NULL)
  1100. {
  1101. pBp = (BRKPT *) malloc (sizeof (BRKPT));
  1102. if (pBp == NULL)
  1103.     return (NULL);
  1104. }
  1105.     /* initialize breakpoint and add to list */
  1106.     pBp->bp_flags = flags;
  1107.     pBp->bp_addr = addr;
  1108.     pBp->bp_task = task;
  1109.     pBp->bp_action = action;
  1110.     pBp->bp_count = count;
  1111.     pBp->bp_callRtn = (void (*)()) callRtn;
  1112.     pBp->bp_callArg = callArg;
  1113.     if ((pBp->bp_flags  & BRK_HARDWARE) == 0)
  1114. pBp->bp_instr = *addr;
  1115.     taskLock (); /* LOCK PREEMPTION */
  1116.     dll_insert(&pBp->bp_chain, &bpList); /* add bp to active list */
  1117.     taskUnlock (); /* UNLOCK PREEMPTION */
  1118.     return (pBp);
  1119.     }
  1120. /*******************************************************************************
  1121. *
  1122. * dbgBrkDisplay - display breakpoints
  1123. *
  1124. * NOMANUAL
  1125. */
  1126. LOCAL void dbgBrkDisplay (void)
  1127.     {
  1128.     dll_t * pDll;
  1129.     BRKPT * pBp;
  1130.     BOOL nobreaks = TRUE; /* flag that no breakpoints are set */
  1131.     for (pDll = dll_head(&bpList); pDll != dll_end(&bpList);
  1132.     pDll = dll_next(pDll))
  1133. {
  1134. /* 
  1135.  * taskLock() and taskUnlock() are useless because of the use of
  1136.  * printf(). So, one or more breakpoints could be deleted by
  1137.  * another task while we are reading the breakpoint list.
  1138.  * If it happens, we can enter an infinite loop.
  1139.  */
  1140. pBp = BP_BASE(pDll);
  1141. nobreaks = FALSE;
  1142. dbgBrkPrint (pBp->bp_addr);
  1143. if (pBp->bp_task == ALL)
  1144.     printf ("   Task: %9s   Count: %2d", "all", pBp->bp_count);
  1145. else
  1146.     printf ("   Task: %#9x   Count: %2d", pBp->bp_task, pBp->bp_count);
  1147. #if DBG_HARDWARE_BP
  1148. /* print informations on hardware breakpoints */
  1149. _dbgBrkDisplayHard (pBp); 
  1150. #endif  /* DBG_HARDWARE_BP */
  1151. if (pBp->bp_flags & BP_HOST )
  1152.     printf ("   (tgtsvr)");
  1153. else
  1154.     {
  1155.     if (pBp->bp_flags & BP_EVENT)
  1156. printf ("   (event)");
  1157.     else if (pBp->bp_flags & BP_SO )
  1158. printf ("   (temporary)");
  1159.     else if (!(pBp->bp_action & WDB_ACTION_NOTIFY ))
  1160. printf ("   (quiet)");
  1161.     }
  1162. printf ("n");
  1163. }
  1164.     if (nobreaks)
  1165. printErr (DBG_NO_BKPTS);
  1166.     }
  1167. /*******************************************************************************
  1168. *
  1169. * dbgBrkPrint - print breakpoint address
  1170. *
  1171. * NOMANUAL
  1172. */
  1173. LOCAL void dbgBrkPrint 
  1174.     (
  1175.     INSTR * addr     /* address of breakpoint */
  1176.     )
  1177.     {
  1178.     char *    label;     /* pointer to name from symbol table */
  1179.     void *    actVal;         /* actual value of label */
  1180.     SYMBOL_ID symId;                        /* symbol identifier */
  1181.     int       displacement;
  1182.     char      demangled [DBG_DEMANGLE_PRINT_LEN+1];
  1183.     char *    labelToPrint;
  1184.     printf ("0x%08x: ", (UINT32) addr); /* print breakpoint address */
  1185.     /* print symbolic address and displacement, if any */
  1186.     if ((symFindSymbol (sysSymTbl, NULL, (void *)addr, 
  1187. SYM_MASK_NONE, SYM_MASK_NONE, &symId) == OK) &&
  1188. (symNameGet (symId, &label) == OK) &&
  1189. (symValueGet (symId, &actVal) == OK))
  1190. {
  1191. labelToPrint = cplusDemangle (label, demangled, sizeof (demangled));
  1192. printf ("%-15s", labelToPrint);
  1193. if ((displacement = (int)addr - (int)actVal) != 0)
  1194.     printf ("+0x%-4x", displacement);
  1195. else
  1196.     printf ("%6s", ""); /* no displacement */
  1197. }
  1198.     else
  1199. printf ("%21s", ""); /* no symbolic address */
  1200.     }
  1201. /*******************************************************************************
  1202. *
  1203. * dbgCheckBreakable - make sure task is breakable
  1204. *
  1205. * Prints an error message if task is unbreakable.
  1206. *
  1207. * RETURNS: OK or ERROR.
  1208. *
  1209. * NOMANUAL
  1210. */
  1211. LOCAL STATUS dbgCheckBreakable
  1212.     (
  1213.     int task /* task id */
  1214.     )
  1215.     {
  1216.     WIND_TCB * pTcb; /* pointer on task TCB */
  1217.     if (task == ERROR)
  1218. return (ERROR);
  1219.     pTcb = taskTcb (task);
  1220.     if (pTcb == NULL)
  1221. {
  1222. printErr (DBG_TASK_IX_NOT_FOUND, task);
  1223. return (ERROR);
  1224. }
  1225.     if ((pTcb->options & VX_UNBREAKABLE) != 0)
  1226. {
  1227. int tid = task == 0 ? taskIdSelf () : task;
  1228. printErr ("Task %#x (%s) is unbreakable.n", tid, taskName (tid));
  1229. return (ERROR);
  1230. }
  1231.     return (OK);
  1232.     }
  1233. /*******************************************************************************
  1234. *
  1235. * dbgTlBreak - print info about a breakpoint 
  1236. *
  1237. * This routine prints info about a breakpoint we have encountered.
  1238. *
  1239. * RETURNS : NA
  1240. *
  1241. * NOMANUAL
  1242. */
  1243. LOCAL void dbgTlBreak
  1244.     (
  1245.     int task, /* taskId */
  1246.     INSTR * pc, /* task's pc */
  1247.     INSTR * addr /* breakpoint's address */
  1248.     )
  1249.     {
  1250.     WIND_TCB * pTcb; /* pointer on task TCB */
  1251.     taskIdDefault (task);
  1252.     pTcb = taskTcb(task);
  1253.     if (pTcb == NULL)
  1254. return;
  1255.     /* print breakpoint info */
  1256.     printErr ("nBreak at ");
  1257.     dbgBrkPrint (addr); /* print the address */
  1258.     printErr ("   Task: %#x (%s)n", task, taskName (task));
  1259.     nextToDsm = pc; /* update l's default list-from */
  1260.     /* 
  1261.      * Reset the flag dbgUnbreakableOld. This flag was set to prevent
  1262.      * encontering breakpoints in this routine (even breakpoint with 
  1263.      * stop action not defined).
  1264.      */
  1265.     dbgUnbreakableOld = FALSE;
  1266.     }
  1267. /*******************************************************************************
  1268. *
  1269. * dbgTlSnglStep - print info about a single-stepping task
  1270. *
  1271. * NOMANUAL
  1272. */
  1273. LOCAL void dbgTlSnglStep
  1274.     (
  1275.     int task /* task id */
  1276.     )
  1277.     {
  1278.     int pc;
  1279.     WIND_TCB * pTcb;
  1280.     dll_t * pDll;
  1281.     dll_t * pNextDll;
  1282.     BRKPT * pBp;
  1283.     /* get pc of the task */
  1284.     pc = (int) _dbgTaskPCGet (task);
  1285.     /* remove (if any) temporary breakpoint set by so or cret instruction */
  1286.     taskLock (); /* LOCK PREEMPTION */
  1287.     for (pDll = dll_head(&bpList); pDll != dll_end(&bpList);
  1288. pDll = pNextDll)
  1289. {
  1290. pNextDll = dll_next(pDll);
  1291. pBp = BP_BASE(pDll);
  1292. if ((pBp->bp_task == (UINT32) task) && 
  1293.     (pBp->bp_addr == (INSTR *) pc) &&
  1294.     (pBp->bp_flags == BP_SO))
  1295.     {
  1296.     wdbDbgBpRemove (pBp);
  1297.     }
  1298. }
  1299.     taskUnlock (); /* UNLOCK PREEMPTION */
  1300.     taskIdDefault (task); /* update default task */
  1301.     pTcb = taskTcb (task);
  1302.     if (pTcb == NULL)
  1303. return;
  1304.     /* print the registers and disassemble next instruction */
  1305.     taskRegsShow (task);
  1306.     if ((pTcb->options & VX_FP_TASK) && dbgPrintFpp)
  1307. {
  1308. /* 
  1309.  * On the other hand fppTaskRegsShow() may modify the FP registers
  1310.  * (this depends of the architecture & compiler: it does happen for
  1311.  * PPC, SH): therefore we need to restore the FP context to what it 
  1312.  * was before fppTaskRegsShow() so that the fppSwapHook() will save
  1313.  * the correct value in the TCB when the next FP task is swapped in.
  1314.  * (see also SPR #7983). This is needed because this routine is
  1315.  * executed in the tExcTask context. tExcTask is spawned without the
  1316.  * VX_FP_TASK option.
  1317.  */
  1318. fppSave(pTcb->pFpContext);
  1319. fppTaskRegsShow (task);
  1320. fppRestore(pTcb->pFpContext);
  1321. }
  1322.     if ((pTcb->options & VX_DSP_TASK) && dbgPrintDsp && 
  1323.         (_func_dspTaskRegsShow != NULL))
  1324. {
  1325. (* _func_dspTaskRegsShow) (task);
  1326. }
  1327. #if (CPU_FAMILY==I80X86)
  1328.     if ((pTcb->options & VX_FP_TASK) && dbgPrintSimd &&
  1329.         (_func_sseTaskRegsShow != NULL))
  1330.         {
  1331.         (* _func_sseTaskRegsShow) (task);
  1332.         }
  1333. #endif /* (CPU_FAMILY==I80X86) */
  1334. #ifdef _WRS_ALTIVEC_SUPPORT
  1335.     if ((pTcb->options & VX_ALTIVEC_TASK) && dbgPrintAltivec)
  1336.         altivecTaskRegsShow (task);
  1337. #endif /* _WRS_ALTIVEC_SUPPORT */
  1338.     (void) dbgList ((INSTR *) pc, 1);
  1339.     nextToDsm = (INSTR *) pc;
  1340.     /* 
  1341.      * Reset the flag dbgUnbreakableOld. This flag was set to prevent
  1342.      * encountering breakpoints (for example if ACTION_STOP was not
  1343.      * specified) in this unbreakable routine.
  1344.      */
  1345.     dbgUnbreakableOld = FALSE;
  1346.     }
  1347. /*******************************************************************************
  1348. *
  1349. * dbgTyAbort - abort the shell from interrupt level
  1350. *
  1351. * NOMANUAL
  1352. */
  1353. LOCAL void dbgTyAbort (void)
  1354.     {
  1355.     excJobAdd ((VOIDFUNCPTR)dbgTlTyAbort, 0,0,0,0,0,0);
  1356.     }
  1357. /*******************************************************************************
  1358. *
  1359. * dbgTlTyAbort - task level portion of shell abort
  1360. *
  1361. * NOMANUAL
  1362. */
  1363. LOCAL void dbgTlTyAbort (void)
  1364.     {
  1365.     tyAbortFuncSet ((FUNCPTR) NULL); /* cancel abort routine */
  1366.     /* reset the standard input and output channels in case they are hung up */
  1367.     ioctl (STD_IN,  FIOFLUSH, 0);
  1368.     ioctl (STD_OUT, FIOFLUSH, 0);
  1369.     ioctl (STD_ERR, FIOFLUSH, 0);
  1370.     tt (shellTaskId);
  1371.     if ((taskRestart (shellTaskId)) != ERROR)
  1372. printErr ("%s restarted.n", taskName (shellTaskId));
  1373.     else
  1374. {
  1375. printErr ("spawning new shell.n");
  1376. if (shellInit (0, TRUE) == ERROR)
  1377.     printErr ("shell spawn failed!n");
  1378. }
  1379.     tyAbortFuncSet ((FUNCPTR) dbgTyAbort); /* set abort routine */
  1380.     }
  1381. /*******************************************************************************
  1382. *
  1383. * l - disassemble and display a specified number of instructions
  1384. *
  1385. * This routine disassembles a specified number of instructions and displays
  1386. * them on standard output.  If the address of an instruction is entered in
  1387. * the system symbol table, the symbol will be displayed as a label for that
  1388. * instruction.  Also, addresses in the opcode field of instructions will be
  1389. * displayed symbolically.
  1390. *
  1391. * To execute, enter:
  1392. * .CS
  1393. *     -> l [address [,count]]
  1394. * .CE
  1395. * If <address> is omitted or zero, disassembly continues from the previous
  1396. * address.  If <count> is omitted or zero, the last specified count is used
  1397. * (initially 10).  As with all values entered via the shell, the address may
  1398. * be typed symbolically.
  1399. *
  1400. * RETURNS: N/A
  1401. *
  1402. * SEE ALSO: 
  1403. * .pG "Target Shell,"
  1404. * windsh,
  1405. * .tG "Shell"
  1406. */
  1407. void l 
  1408.     (
  1409.     INSTR * addr,       /* address of first instruction to disassemble */
  1410. /* if 0, continue from the last instruction */
  1411. /* disassembled on the last call to l */
  1412.     int    count /* number of instruction to disassemble */
  1413. /* if 0, use the same as the last call to l */
  1414.     )
  1415.     {
  1416.     addr = (INSTR *) ROUND_DOWN (addr, DBG_INST_ALIGN); /* force alignment */
  1417.     /* set new start address and instruction count if specified */
  1418.     if ((int) addr != 0)
  1419. nextToDsm = addr;
  1420.     if (count != 0)
  1421. dfltCount = count;
  1422.     nextToDsm = dbgList (nextToDsm, dfltCount); /* disassemble n instructions */
  1423.     }
  1424. /*******************************************************************************
  1425. *
  1426. * dbgList - disassemble and list n instructions
  1427. *
  1428. * This routine disassembles some number of instructions, using dsmLib.
  1429. * The normal user interface is through the routine 'l', rather than through
  1430. * this routine.
  1431. *
  1432. * RETURNS: Pointer to instruction following last instruction disassembled.
  1433. *
  1434. * NOMANUAL
  1435. */
  1436. LOCAL INSTR * dbgList 
  1437.     (
  1438.     INSTR * addr, /* address of first instruction to disassemble */
  1439.     int count  /* number of intructions to dissamble */
  1440.     )
  1441.     {
  1442.     char *    label;   /* pointer to symbol table copy of symbol name string */
  1443.     void *    actVal;  /* actual address of symbol found */
  1444.     SYMBOL_ID symId;   /* symbol identifier */
  1445.     int       ix;
  1446.     char      demangled[DBG_DEMANGLE_PRINT_LEN + 1];
  1447.     char *    labelToPrint;
  1448.     for (ix = 0; ix < count; ix++)
  1449. {
  1450. if ((symFindSymbol (sysSymTbl, NULL, (void *)addr, 
  1451.     SYM_MASK_NONE, SYM_MASK_NONE, &symId) == OK) &&
  1452.     (symNameGet (symId, &label) == OK) &&
  1453.     (symValueGet (symId, &actVal) == OK) &&
  1454.     (actVal == (void *)addr))
  1455.     {
  1456.     labelToPrint = cplusDemangle(label, demangled, sizeof (demangled));
  1457. #if (CPU_FAMILY == SH)
  1458.     printf ("               %s:n", labelToPrint);
  1459. #else
  1460.     printf (" %s:n", labelToPrint);
  1461. #endif
  1462.     }
  1463. if (_dbgDsmInstRtn == (FUNCPTR) NULL)
  1464.     printErr ("dbgList: no disassembler.n");
  1465. else
  1466.     addr += (*_dbgDsmInstRtn) (addr, (int)addr, dbgPrintAdrs);
  1467. }
  1468.     return (addr);
  1469.     }
  1470. /*******************************************************************************
  1471. *
  1472. * dbgPrintAdrs - prints addresses as symbols, if an exact match can be found
  1473. *
  1474. * NOMANUAL
  1475. */
  1476. LOCAL void dbgPrintAdrs 
  1477.     (
  1478.     int address  /* address to print */
  1479.     )
  1480.     {
  1481.     char *    label;  /* pointer to symbol table copy of symbol name string */
  1482.     void *    actVal; /* actual address of symbol found */
  1483.     SYMBOL_ID symId;  /* symbol identifier */
  1484.     char      demangled[DBG_DEMANGLE_PRINT_LEN + 1];
  1485.     char *    labelToPrint;
  1486.     if ((symFindSymbol (sysSymTbl, NULL, (void *)address, 
  1487. SYM_MASK_NONE, SYM_MASK_NONE, &symId) == OK) &&
  1488. (symNameGet (symId, &label) == OK) &&
  1489. (symValueGet (symId, &actVal) == OK) &&
  1490. (actVal == (void *)address))
  1491. {
  1492. labelToPrint = cplusDemangle(label, demangled, sizeof (demangled));
  1493. printf ("%s", labelToPrint);
  1494. }
  1495.     else
  1496. printf ("0x%08x", address);
  1497.     }
  1498. /*******************************************************************************
  1499. *
  1500. * tt - display a stack trace of a task
  1501. *
  1502. * This routine displays a list of the nested routine calls that the specified
  1503. * task is in.  Each routine call and its parameters are shown.
  1504. *
  1505. * If <taskNameOrId> is not specified or zero, the last task referenced is
  1506. * assumed.  The tt() routine can only trace the stack of a task other than
  1507. * itself.  For instance, when tt() is called from the shell, it cannot trace
  1508. * the shell's stack.
  1509. *
  1510. * EXAMPLE
  1511. * .CS
  1512. *     -> tt "logTask"
  1513. *      3ab92 _vxTaskEntry   +10 : _logTask (0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
  1514. *       ee6e _logTask       +12 : _read (5, 3f8a10, 20)
  1515. *       d460 _read          +10 : _iosRead (5, 3f8a10, 20)
  1516. *       e234 _iosRead       +9c : _pipeRead (3fce1c, 3f8a10, 20)
  1517. *      23978 _pipeRead      +24 : _semTake (3f8b78)
  1518. *     value = 0 = 0x0
  1519. * .CE
  1520. * This indicates that logTask() is currently in semTake() (with
  1521. * one parameter) and was called by pipeRead() (with three parameters),
  1522. * which was called by iosRead() (with three parameters), and so on.
  1523. *
  1524. * INTERNAL
  1525. * This higher-level symbolic stack trace is built on top of the
  1526. * lower-level routines provided by trcLib.
  1527. *
  1528. * CAVEAT
  1529. * In order to do the trace, some assumptions are made.  In general, the
  1530. * trace will work for all C language routines and for assembly language
  1531. * routines that start with a LINK instruction.  Some C compilers require
  1532. * specific flags to generate the LINK first.  Most VxWorks assembly language
  1533. * routines include LINK instructions for this reason.  The trace facility
  1534. * may produce inaccurate results or fail completely if the routine is
  1535. * written in a language other than C, the routine's entry point is
  1536. * non-standard, or the task's stack is corrupted.  Also, all parameters are
  1537. * assumed to be 32-bit quantities, so structures passed as parameters will
  1538. * be displayed as f2longfP integers.
  1539. *
  1540. * RETURNS:
  1541. * OK, or ERROR if the task does not exist.
  1542. *
  1543. * SEE ALSO:
  1544. * .pG "Target Shell,"
  1545. * windsh,
  1546. * .tG "Shell"
  1547. */
  1548. STATUS tt
  1549.     (
  1550.     int taskNameOrId /* task name or task ID */
  1551.     )
  1552.     {
  1553.     REG_SET regSet;
  1554.     BOOL resumeIt = FALSE; /* flag to remember if resuming is necessary */
  1555.     int tid = taskIdFigure (taskNameOrId); /* convert to task id */
  1556.     if (tid == ERROR)
  1557. {
  1558. printErr (DBG_TASK_NOT_FOUND);
  1559. return (ERROR);
  1560. }
  1561.     tid = taskIdDefault (tid); /* set default task id */
  1562.     /* get caller task's id and make sure it is not the task to be traced */
  1563.     if (tid == taskIdSelf () || tid == 0)
  1564. {
  1565. printErr ("Sorry, traces of my own stack begin at tt ().n");
  1566. return (ERROR);
  1567. }
  1568.     /* make sure the task exists */
  1569.     if (taskIdVerify (tid) != OK)
  1570. {
  1571. printErr ("Can't trace task %#x: invalid task id.n", tid);
  1572. return (ERROR);
  1573. }
  1574.     /* if the task is not already suspended, suspend it while we trace it */
  1575.     if (!taskIsSuspended (tid))
  1576. {
  1577. resumeIt = TRUE; /* we want to resume it later */
  1578. taskSuspend (tid); /* suspend the task if need be */
  1579. }
  1580.     /* trace the stack */
  1581.     taskRegsGet (tid, &regSet);
  1582.     trcStack (&regSet, (FUNCPTR) dbgPrintCall, tid);
  1583.     if (resumeIt)
  1584. taskResume (tid); /* resume task if we suspended it */
  1585.     return (OK);
  1586.     }
  1587.     
  1588. /*******************************************************************************
  1589. *
  1590. * dbgPrintCall - print a stack frame
  1591. *
  1592. * This routine is called by trcStack to print each level in turn.
  1593. * If nargs is specified as 0, then a default number of args (trcDefaultArgs)
  1594. * is printed in brackets ("[..]"), since this often indicates that the
  1595. * number of args is unknown.
  1596. *
  1597. * NOMANUAL - also used by shellSigHandler
  1598. */
  1599. void dbgPrintCall
  1600.     (
  1601.     INSTR * callAdrs, /* address from which function was called */
  1602.     int funcAdrs, /* address of function called */
  1603.     int nargs, /* number of arguments in function call */
  1604.     UINT32 * args /* pointer to function args */
  1605.     )
  1606.     {
  1607.     int       ix;
  1608.     SYMBOL_ID symId;                                     /* symbol identifier */
  1609.     char *    name;  /* pointer to symbol tbl copy of function name goes here */
  1610.     void *    val;           /* address of named fn goes here */
  1611.     BOOL      doingDefault = FALSE;
  1612.     char      demangled [DBG_DEMANGLE_PRINT_LEN + 1];
  1613.     char *    nameToPrint;
  1614.     /* print call address and name of calling function plus offset */
  1615.     printErr ("%6x ", callAdrs); /* print address from which called */
  1616.     if ((symFindSymbol (sysSymTbl, NULL, (void *)callAdrs, 
  1617. SYM_MASK_NONE, SYM_MASK_NONE, &symId) == OK) &&
  1618. (symNameGet (symId, &name) == OK) &&
  1619. (symValueGet (symId, &val) == OK))
  1620. {
  1621. nameToPrint = cplusDemangle (name, demangled, sizeof (demangled));
  1622. printErr ("%-15s+%-3x: ", nameToPrint, (int)callAdrs - (int)val);
  1623. }
  1624.     else
  1625. #if CPU_FAMILY == ARM
  1626. /* make things line up properly */
  1627.         printErr ("                   : ");
  1628. #else
  1629. printErr ("                     : ");
  1630. #endif
  1631.     /* print function address/name */
  1632.     if ((symFindSymbol (sysSymTbl, NULL, (void *)funcAdrs, 
  1633. SYM_MASK_NONE, SYM_MASK_NONE, &symId) == OK) &&
  1634. (symNameGet (symId, &name) == OK) &&
  1635. (symValueGet (symId, &val) == OK) &&
  1636. (val == (void *)funcAdrs))
  1637. {
  1638. nameToPrint = cplusDemangle (name, demangled, sizeof (demangled));
  1639. printErr ("%s (", nameToPrint); /* print function name */
  1640. }
  1641.     else
  1642. printErr ("%x (", funcAdrs); /* print function address */
  1643.     /* if no args are specified, print out default number (see doc at top) */
  1644.     if ((nargs == 0) && (trcDefaultArgs != 0))
  1645. {
  1646. doingDefault = TRUE;
  1647. nargs = trcDefaultArgs;
  1648. printErr ("[");
  1649. }
  1650.     /* print args */
  1651.     for (ix = 0; ix < nargs; ix++)
  1652. {
  1653. if (ix > 0)
  1654.     printErr (", ");
  1655. if (args [ix] == 0)
  1656.     printErr ("0");
  1657. else if ((symFindSymbol (sysSymTbl, NULL, (void *)args[ix], 
  1658.  SYM_MASK_NONE, SYM_MASK_NONE, &symId) == OK) &&
  1659.  (symNameGet (symId, &name) == OK) &&
  1660.  (symValueGet (symId, &val) == OK) &&
  1661.  (val == (void *)args [ix]))
  1662.     {
  1663.     nameToPrint = cplusDemangle (name, demangled, sizeof (demangled));
  1664.     printErr ("&%s", nameToPrint); /* print argument name */
  1665.     }
  1666. else
  1667.     printErr ("%x", args [ix]);
  1668. }
  1669.     if (doingDefault)
  1670. printErr ("]");
  1671.     printErr (")n");
  1672.     }
  1673. /******************************************************************************
  1674. *
  1675. * dbgE - code to support the windview "e" command
  1676. * This routine is called each time a windview breakpoint is encountered
  1677. * This is a temporary solution. This routine should be moved in windview 
  1678. * code.
  1679. *
  1680. * RETURNS : NA
  1681. *
  1682. * NOMANUAL
  1683. */ 
  1684. LOCAL void dbgE
  1685.     (
  1686.     EVT_CALL_ARGS * pEvtCallArgs,
  1687.     REG_SET * pRegisters
  1688.     )
  1689.     {
  1690.     int (*conditionFunc)() = (int (*)())pEvtCallArgs->evtRtn;
  1691.     if (conditionFunc == NULL || conditionFunc (pEvtCallArgs->evtRtnArg) == OK)
  1692.         EVT_CTX_BUF (pEvtCallArgs->eventId, pRegisters->reg_pc, 0, NULL);
  1693.     }
  1694. /*******************************************************************************
  1695. *
  1696. * dbgTargetNotify - notify the target when a breakpoint is encountered 
  1697. *
  1698. * This routine is called to notify the shell user through the console
  1699. * when a breakpoint is encountered. Depending on the type of breakpoint, 
  1700. * the action is different.
  1701. *
  1702. * RETURNS: N/A.
  1703. *
  1704. * NOMANUAL
  1705. */
  1706. LOCAL void dbgTargetNotify
  1707.     (
  1708.     UINT32 flag, /* type of breakpoint (step over, step ...) */
  1709.     UINT32 addr, /* breakpoint addr */
  1710.     REG_SET *  pRegisters /* task registers before exception */
  1711.     )
  1712.     {
  1713.     /* 
  1714.      * Prevent excTask to encounter a breakpoint event if there is not
  1715.      * ACTION_STOP. This is necessary to avoid recursive loop if a 
  1716.      * NOTIFY breakpoint could be encountered by dbgTlSnglStep or
  1717.      * dbgTlBreak. dbgUnbreakableOld should be restored to FALSE state
  1718.      * in dbgTlSnglStep and dbgTlBreak routines.
  1719.      */
  1720.     dbgUnbreakableOld = TRUE;
  1721.     /* check the breakpoint flag in order to determine the action to perform */
  1722.     if (flag & (BP_SO | BP_STEP))
  1723. excJobAdd (dbgTlSnglStep, (UINT32) taskIdCurrent, 0, 0, 0, 0, 0);
  1724.     else
  1725. excJobAdd (dbgTlBreak, (UINT32) taskIdCurrent, (UINT32) pRegisters->pc, 
  1726. addr, 0, 0, 0);
  1727.     }