1/*
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31/*
32 * HISTORY
33 *
34 * Revision 1.1.1.1  1998/09/22 21:05:47  wsanchez
35 * Import of Mac OS X kernel (~semeria)
36 *
37 * Revision 1.1.1.1  1998/03/07 02:26:09  wsanchez
38 * Import of OSF Mach kernel (~mburg)
39 *
40 * Revision 1.2.18.1  1997/03/27  18:46:29  barbou
41 * 	ri-osc CR1558: enable use of breakpoint counts even when no
42 * 	condition given.
43 * 	[1995/09/20  15:24:24  bolinger]
44 * 	[97/02/25            barbou]
45 *
46 * Revision 1.2.6.2  1996/01/09  19:15:34  devrcs
47 * 	Change 'register c' to 'register int c'.
48 * 	[1995/12/01  21:42:00  jfraser]
49 *
50 * 	Merged '64-bit safe' changes from DEC alpha port.
51 * 	[1995/11/21  18:02:54  jfraser]
52 *
53 * Revision 1.2.6.1  1994/09/23  01:18:27  ezf
54 * 	change marker to not FREE
55 * 	[1994/09/22  21:09:37  ezf]
56 *
57 * Revision 1.2.2.4  1993/08/11  20:37:33  elliston
58 * 	Add ANSI Prototypes.  CR #9523.
59 * 	[1993/08/11  03:32:57  elliston]
60 *
61 * Revision 1.2.2.3  1993/07/27  18:26:59  elliston
62 * 	Add ANSI prototypes.  CR #9523.
63 * 	[1993/07/27  18:11:12  elliston]
64 *
65 * Revision 1.2.2.2  1993/06/09  02:19:53  gm
66 * 	Added to OSF/1 R1.3 from NMK15.0.
67 * 	[1993/06/02  20:56:04  jeffc]
68 *
69 * Revision 1.2  1993/04/19  16:01:51  devrcs
70 * 	Changes from mk78:
71 * 	Changed errant call of db_error in db_cond_cmd() to db_printf/db_error.
72 * 	[92/05/20            jfriedl]
73 * 	[93/02/02            bruel]
74 *
75 * Revision 1.1  1992/09/30  02:00:58  robert
76 * 	Initial revision
77 *
78 * $EndLog$
79 */
80/* CMU_HIST */
81/*
82 * Revision 2.2  91/10/09  15:59:09  af
83 * 	 Revision 2.1.3.1  91/10/05  13:05:38  jeffreyh
84 * 	 	Created to support conditional break point and command execution.
85 * 	 	[91/08/29            tak]
86 *
87 * Revision 2.1.3.1  91/10/05  13:05:38  jeffreyh
88 * 	Created to support conditional break point and command execution.
89 * 	[91/08/29            tak]
90 *
91 */
92/* CMU_ENDHIST */
93/*
94 * Mach Operating System
95 * Copyright (c) 1991,1990 Carnegie Mellon University
96 * All Rights Reserved.
97 *
98 * Permission to use, copy, modify and distribute this software and its
99 * documentation is hereby granted, provided that both the copyright
100 * notice and this permission notice appear in all copies of the
101 * software, derivative works or modified versions, and any portions
102 * thereof, and that both notices appear in supporting documentation.
103 *
104 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
105 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
106 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
107 *
108 * Carnegie Mellon requests users of this software to return to
109 *
110 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
111 *  School of Computer Science
112 *  Carnegie Mellon University
113 *  Pittsburgh PA 15213-3890
114 *
115 * any improvements or extensions that they make and grant Carnegie Mellon
116 * the rights to redistribute these changes.
117 */
118/*
119 */
120
121#include <machine/db_machdep.h>
122#include <machine/setjmp.h>
123#include <kern/misc_protos.h>
124
125#include <ddb/db_lex.h>
126#include <ddb/db_break.h>
127#include <ddb/db_command.h>
128#include <ddb/db_cond.h>
129#include <ddb/db_expr.h>
130#include <ddb/db_output.h>		/* For db_printf() */
131
132#define DB_MAX_COND	10		/* maximum conditions to be set */
133
134int   db_ncond_free = DB_MAX_COND;			/* free condition */
135struct db_cond {
136	int	c_size;					/* size of cond */
137	char	c_cond_cmd[DB_LEX_LINE_SIZE];		/* cond & cmd */
138} db_cond[DB_MAX_COND];
139
140void
141db_cond_free(db_thread_breakpoint_t bkpt)
142{
143	if (bkpt->tb_cond > 0) {
144	    db_cond[bkpt->tb_cond-1].c_size = 0;
145	    db_ncond_free++;
146	    bkpt->tb_cond = 0;
147	}
148}
149
150extern jmp_buf_t *db_recover;
151
152boolean_t
153db_cond_check(db_thread_breakpoint_t bkpt)
154{
155	register  struct db_cond *cp;
156	db_expr_t value;
157	int	  t;
158	jmp_buf_t db_jmpbuf;
159
160	if (bkpt->tb_cond <= 0) {		/* no condition */
161		if (--(bkpt->tb_count) > 0)
162			return(FALSE);
163		bkpt->tb_count = bkpt->tb_init_count;
164	    return(TRUE);
165	}
166	db_dot = PC_REGS(DDB_REGS);
167	db_prev = db_dot;
168	db_next = db_dot;
169	if (_setjmp(db_recover = &db_jmpbuf)) {
170	    /*
171	     * in case of error, return true to enter interactive mode
172	     */
173	    return(TRUE);
174	}
175
176	/*
177	 * switch input, and evalutate condition
178	 */
179	cp = &db_cond[bkpt->tb_cond - 1];
180	db_switch_input(cp->c_cond_cmd, cp->c_size);
181	if (!db_expression(&value)) {
182	    db_printf("error: condition evaluation error\n");
183	    return(TRUE);
184	}
185	if (value == 0 || --(bkpt->tb_count) > 0)
186	    return(FALSE);
187
188	/*
189	 * execute a command list if exist
190	 */
191	bkpt->tb_count = bkpt->tb_init_count;
192	if ((t = db_read_token()) != tEOL) {
193	    db_unread_token(t);
194	    return(db_exec_cmd_nest(0, 0));
195	}
196	return(TRUE);
197}
198
199void
200db_cond_print(db_thread_breakpoint_t bkpt)
201{
202	register char *p, *ep;
203	register struct db_cond *cp;
204
205	if (bkpt->tb_cond <= 0)
206	    return;
207	cp = &db_cond[bkpt->tb_cond-1];
208	p = cp->c_cond_cmd;
209	ep = p + cp->c_size;
210	while (p < ep) {
211	    if (*p == '\n' || *p == 0)
212		break;
213	    db_putchar(*p++);
214	}
215}
216
217void
218db_cond_cmd(void)
219{
220	register  int c;
221	register  struct db_cond *cp;
222	register  char *p;
223	db_expr_t value;
224	db_thread_breakpoint_t bkpt;
225
226	if (db_read_token() != tHASH || db_read_token() != tNUMBER) {
227	    db_printf("#<number> expected instead of \"%s\"\n", db_tok_string);
228	    db_error(0);
229	    return;
230	}
231	if ((bkpt = db_find_breakpoint_number(db_tok_number, 0)) == 0) {
232	    db_printf("No such break point #%d\n", db_tok_number);
233	    db_error(0);
234	    return;
235	}
236	/*
237	 * if the break point already has a condition, free it first
238	 */
239	if (bkpt->tb_cond > 0) {
240	    cp = &db_cond[bkpt->tb_cond - 1];
241	    db_cond_free(bkpt);
242	} else {
243	    if (db_ncond_free <= 0) {
244		db_error("Too many conditions\n");
245		return;
246	    }
247	    for (cp = db_cond; cp < &db_cond[DB_MAX_COND]; cp++)
248		if (cp->c_size == 0)
249		    break;
250	    if (cp >= &db_cond[DB_MAX_COND])
251		panic("bad db_cond_free");
252	}
253	for (c = db_read_char(); c == ' ' || c == '\t'; c = db_read_char());
254	for (p = cp->c_cond_cmd; c >= 0; c = db_read_char())
255	    *p++ = c;
256	/*
257	 * switch to saved data and call db_expression to check the condition.
258	 * If no condition is supplied, db_expression will return false.
259	 * In this case, clear previous condition of the break point.
260         * If condition is supplied, set the condition to the permanent area.
261	 * Note: db_expression will not return here, if the condition
262	 *       expression is wrong.
263	 */
264	db_switch_input(cp->c_cond_cmd, p - cp->c_cond_cmd);
265	if (!db_expression(&value)) {
266	    /* since condition is already freed, do nothing */
267	    db_flush_lex();
268	    return;
269	}
270	db_flush_lex();
271	db_ncond_free--;
272	cp->c_size = p - cp->c_cond_cmd;
273	bkpt->tb_cond = (cp - db_cond) + 1;
274}
275