blob: cb048b8797d691a79ad0d9006c29f2a2458d18ed [file] [log] [blame]
sewardj35421a32004-07-05 13:12:34 +00001
2/*---------------------------------------------------------------*/
3/*--- ---*/
4/*--- This file (vex_util.c) is ---*/
5/*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/
6/*--- ---*/
7/*---------------------------------------------------------------*/
8
9#include "libjit_basictypes.h"
10#include "jit_globals.h"
11#include "vex_util.h"
12
13
14/*---------------------------------------------------------*/
15/*--- Storage ---*/
16/*---------------------------------------------------------*/
17
sewardjce605f92004-07-05 14:39:15 +000018/* Try to keep this as low as possible -- in particular, less than the
19 size of the smallest L2 cache we might encounter. At 50000, my VIA
20 Nehemiah 1 GHz (a weedy machine) can satisfy 27 million calls/
21 second to LibVEX_Alloc(16) -- that is, allocate memory at over 400
22 MByte/sec. Once the size increases enough to fall out of the cache
23 into memory, the rate falls by about a factor of 3.
24*/
25#define N_STORAGE_BYTES 50000
sewardj35421a32004-07-05 13:12:34 +000026
27static Char storage[N_STORAGE_BYTES];
28static Int storage_used = 0;
29
sewardjce605f92004-07-05 14:39:15 +000030/* Gather statistics. */
31static Int storage_bytes_allocd = 0;
32static Int storage_count_allocs = 0;
33
34static ULong storage_bytes_allocd_TOT = 0;
35static ULong storage_count_allocs_TOT = 0;
36
37
38
sewardj35421a32004-07-05 13:12:34 +000039/* Exported to library client. */
40
41void* LibVEX_Alloc ( Int nbytes )
42{
43 vassert(vex_initdone);
44 vassert(nbytes > 0);
sewardjce605f92004-07-05 14:39:15 +000045 nbytes = (nbytes + 7) & ~7;
sewardj35421a32004-07-05 13:12:34 +000046 if (storage_used + nbytes > N_STORAGE_BYTES)
47 vpanic("VEX storage exhausted.\n"
48 "Increase N_STORAGE_BYTES and recompile.");
sewardjce605f92004-07-05 14:39:15 +000049 storage_count_allocs++;
50 storage_bytes_allocd += nbytes;
sewardj35421a32004-07-05 13:12:34 +000051 storage_used += nbytes;
52 return (void*)(&storage[storage_used - nbytes]);
53}
54
55/* Exported to library client. */
56
sewardjce605f92004-07-05 14:39:15 +000057void LibJIT_Clear ( Bool verb )
sewardj35421a32004-07-05 13:12:34 +000058{
59 vassert(vex_initdone);
sewardjce605f92004-07-05 14:39:15 +000060 storage_bytes_allocd_TOT += (ULong)storage_bytes_allocd;
61 storage_count_allocs_TOT += (ULong)storage_count_allocs;
62 if (verb) {
63 vex_printf("vex storage: total %lld (%lld), curr %d (%d)\n",
64 storage_bytes_allocd_TOT, storage_count_allocs_TOT,
65 storage_bytes_allocd, storage_count_allocs );
66 }
sewardj35421a32004-07-05 13:12:34 +000067 storage_used = 0;
sewardjce605f92004-07-05 14:39:15 +000068 storage_bytes_allocd = 0;
69 storage_count_allocs = 0;
sewardj35421a32004-07-05 13:12:34 +000070}
71
72
73
74/*---------------------------------------------------------*/
75/*--- Bombing out ---*/
76/*---------------------------------------------------------*/
77
78__attribute__ ((noreturn))
79void vex_assert_fail ( const Char* expr,
80 const Char* file, Int line, const Char* fn )
81{
82 vex_printf( "\nvex: %s:%d (%s): Assertion `%s' failed.\n",
83 file, line, fn, expr );
84 (*vex_failure_exit)();
85}
86
87__attribute__ ((noreturn))
sewardjce605f92004-07-05 14:39:15 +000088void vpanic ( Char* str )
sewardj35421a32004-07-05 13:12:34 +000089{
90 vex_printf("\nvex: the `impossible' happened:\n %s\n", str);
91 (*vex_failure_exit)();
92}
93
94
95/*---------------------------------------------------------*/
96/*--- vex_printf ---*/
97/*---------------------------------------------------------*/
98
99/* This should be the only <...> include in the entire VEX library.
100 New code for vex_util.c should go above this point. */
101#include <stdarg.h>
102
103/* ---------------------------------------------------------------------
104 printf implementation. The key function, vg_vprintf(), emits chars
105 into a caller-supplied function. Distantly derived from:
106
107 vprintf replacement for Checker.
108 Copyright 1993, 1994, 1995 Tristan Gingold
109 Written September 1993 Tristan Gingold
110 Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
111
112 (Checker itself was GPL'd.)
113 ------------------------------------------------------------------ */
114
115static Char vex_toupper ( Char c )
116{
117 if (c >= 'a' && c <= 'z')
118 return c + ('A' - 'a');
119 else
120 return c;
121}
122
123static Int vex_strlen ( const Char* str )
124{
125 Int i = 0;
126 while (str[i] != 0) i++;
127 return i;
128}
129
130
131/* Some flags. */
132#define VG_MSG_SIGNED 1 /* The value is signed. */
133#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
134#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
135#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
136#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
137
138/* Copy a string into the buffer. */
139static UInt
140myvprintf_str ( void(*send)(Char), Int flags, Int width, Char* str,
141 Bool capitalise )
142{
143# define MAYBE_TOUPPER(ch) (capitalise ? vex_toupper(ch) : (ch))
144 UInt ret = 0;
145 Int i, extra;
146 Int len = vex_strlen(str);
147
148 if (width == 0) {
149 ret += len;
150 for (i = 0; i < len; i++)
151 send(MAYBE_TOUPPER(str[i]));
152 return ret;
153 }
154
155 if (len > width) {
156 ret += width;
157 for (i = 0; i < width; i++)
158 send(MAYBE_TOUPPER(str[i]));
159 return ret;
160 }
161
162 extra = width - len;
163 if (flags & VG_MSG_LJUSTIFY) {
164 ret += extra;
165 for (i = 0; i < extra; i++)
166 send(' ');
167 }
168 ret += len;
169 for (i = 0; i < len; i++)
170 send(MAYBE_TOUPPER(str[i]));
171 if (!(flags & VG_MSG_LJUSTIFY)) {
172 ret += extra;
173 for (i = 0; i < extra; i++)
174 send(' ');
175 }
176
177# undef MAYBE_TOUPPER
178
179 return ret;
180}
181
182/* Write P into the buffer according to these args:
183 * If SIGN is true, p is a signed.
184 * BASE is the base.
185 * If WITH_ZERO is true, '0' must be added.
186 * WIDTH is the width of the field.
187 */
188static UInt
189myvprintf_int64 ( void(*send)(Char), Int flags, Int base, Int width, ULong p)
190{
191 Char buf[40];
192 Int ind = 0;
193 Int i, nc = 0;
194 Bool neg = False;
195 Char *digits = "0123456789ABCDEF";
196 UInt ret = 0;
197
198 if (base < 2 || base > 16)
199 return ret;
200
201 if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
202 p = - (Long)p;
203 neg = True;
204 }
205
206 if (p == 0)
207 buf[ind++] = '0';
208 else {
209 while (p > 0) {
210 if (flags & VG_MSG_COMMA && 10 == base &&
211 0 == (ind-nc) % 3 && 0 != ind)
212 {
213 buf[ind++] = ',';
214 nc++;
215 }
216 buf[ind++] = digits[p % base];
217 p /= base;
218 }
219 }
220
221 if (neg)
222 buf[ind++] = '-';
223
224 if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
225 for(; ind < width; ind++) {
226 vassert(ind < 39);
227 buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
228 }
229 }
230
231 /* Reverse copy to buffer. */
232 ret += ind;
233 for (i = ind -1; i >= 0; i--) {
234 send(buf[i]);
235 }
236 if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
237 for(; ind < width; ind++) {
238 ret++;
239 send(' '); // Never pad with zeroes on RHS -- changes the value!
240 }
241 }
242 return ret;
243}
244
245
246/* A simple vprintf(). */
247static
248UInt vprintf_wrk ( void(*send)(Char), const Char *format, va_list vargs )
249{
250 UInt ret = 0;
251 int i;
252 int flags;
253 int width;
254 Bool is_long;
255
256 /* We assume that vargs has already been initialised by the
257 caller, using va_start, and that the caller will similarly
258 clean up with va_end.
259 */
260
261 for (i = 0; format[i] != 0; i++) {
262 if (format[i] != '%') {
263 send(format[i]);
264 ret++;
265 continue;
266 }
267 i++;
268 /* A '%' has been found. Ignore a trailing %. */
269 if (format[i] == 0)
270 break;
271 if (format[i] == '%') {
272 /* `%%' is replaced by `%'. */
273 send('%');
274 ret++;
275 continue;
276 }
277 flags = 0;
278 is_long = False;
279 width = 0; /* length of the field. */
280 if (format[i] == '(') {
281 flags |= VG_MSG_PAREN;
282 i++;
283 }
284 /* If ',' follows '%', commas will be inserted. */
285 if (format[i] == ',') {
286 flags |= VG_MSG_COMMA;
287 i++;
288 }
289 /* If '-' follows '%', justify on the left. */
290 if (format[i] == '-') {
291 flags |= VG_MSG_LJUSTIFY;
292 i++;
293 }
294 /* If '0' follows '%', pads will be inserted. */
295 if (format[i] == '0') {
296 flags |= VG_MSG_ZJUSTIFY;
297 i++;
298 }
299 /* Compute the field length. */
300 while (format[i] >= '0' && format[i] <= '9') {
301 width *= 10;
302 width += format[i++] - '0';
303 }
304 while (format[i] == 'l') {
305 i++;
306 is_long = True;
307 }
308
309 switch (format[i]) {
310 case 'd': /* %d */
311 flags |= VG_MSG_SIGNED;
312 if (is_long)
313 ret += myvprintf_int64(send, flags, 10, width,
314 (ULong)(va_arg (vargs, Long)));
315 else
316 ret += myvprintf_int64(send, flags, 10, width,
317 (ULong)(va_arg (vargs, Int)));
318 break;
319 case 'u': /* %u */
320 if (is_long)
321 ret += myvprintf_int64(send, flags, 10, width,
322 (ULong)(va_arg (vargs, ULong)));
323 else
324 ret += myvprintf_int64(send, flags, 10, width,
325 (ULong)(va_arg (vargs, UInt)));
326 break;
327 case 'p': /* %p */
328 ret += 2;
329 send('0');
330 send('x');
331 ret += myvprintf_int64(send, flags, 16, width,
332 (ULong)((UInt)va_arg (vargs, void *)));
333 break;
334 case 'x': /* %x */
335 if (is_long)
336 ret += myvprintf_int64(send, flags, 16, width,
337 (ULong)(va_arg (vargs, ULong)));
338 else
339 ret += myvprintf_int64(send, flags, 16, width,
340 (ULong)(va_arg (vargs, UInt)));
341 break;
342 case 'c': /* %c */
343 ret++;
344 send(va_arg (vargs, int));
345 break;
346 case 's': case 'S': { /* %s */
347 char *str = va_arg (vargs, char *);
348 if (str == (char*) 0) str = "(null)";
349 ret += myvprintf_str(send, flags, width, str, format[i]=='S');
350 break;
351 }
352# if 0
353 case 'y': { /* %y - print symbol */
354 Char buf[100];
355 Char *cp = buf;
356 Addr a = va_arg(vargs, Addr);
357
358 if (flags & VG_MSG_PAREN)
359 *cp++ = '(';
360 if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
361 if (flags & VG_MSG_PAREN) {
362 cp += VG_(strlen)(cp);
363 *cp++ = ')';
364 *cp = '\0';
365 }
366 ret += myvprintf_str(send, flags, width, buf, 0);
367 }
368 break;
369 }
370# endif
371 default:
372 break;
373 }
374 }
375 return ret;
376}
377
378
379/* A general replacement for printf(). Note that only low-level
380 debugging info should be sent via here. The official route is to
381 to use vg_message(). This interface is deprecated.
382*/
383static Char myprintf_buf[1000];
384static Int n_myprintf_buf;
385
386static void add_to_myprintf_buf ( Char c )
387{
388 if (c == '\n' || n_myprintf_buf >= 1000-10 /*paranoia*/ ) {
389 (*vex_log_bytes)( myprintf_buf, vex_strlen(myprintf_buf) );
390 n_myprintf_buf = 0;
391 myprintf_buf[n_myprintf_buf] = 0;
392 }
393 myprintf_buf[n_myprintf_buf++] = c;
394 myprintf_buf[n_myprintf_buf] = 0;
395}
396
397UInt vex_printf ( const char *format, ... )
398{
399 UInt ret;
400 va_list vargs;
401 va_start(vargs,format);
402
403 n_myprintf_buf = 0;
404 myprintf_buf[n_myprintf_buf] = 0;
405 ret = vprintf_wrk ( add_to_myprintf_buf, format, vargs );
406
407 if (n_myprintf_buf > 0) {
408 (*vex_log_bytes)( myprintf_buf, n_myprintf_buf );
409 }
410
411 va_end(vargs);
412
413 return ret;
414}
415
416
417/*---------------------------------------------------------------*/
418/*--- end vex_util.c ---*/
419/*---------------------------------------------------------------*/