blob: 98f41c30a0945a5b0647d9642ae8825e056ea55c [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
sewardj887a11a2004-07-05 17:26:47 +00009#include "libvex_basictypes.h"
sewardj41f43bc2004-07-08 14:23:22 +000010#include "libvex.h"
11
sewardj887a11a2004-07-05 17:26:47 +000012#include "vex_globals.h"
sewardj35421a32004-07-05 13:12:34 +000013#include "vex_util.h"
14
15
16/*---------------------------------------------------------*/
17/*--- Storage ---*/
18/*---------------------------------------------------------*/
19
sewardjce605f92004-07-05 14:39:15 +000020/* Try to keep this as low as possible -- in particular, less than the
21 size of the smallest L2 cache we might encounter. At 50000, my VIA
22 Nehemiah 1 GHz (a weedy machine) can satisfy 27 million calls/
23 second to LibVEX_Alloc(16) -- that is, allocate memory at over 400
24 MByte/sec. Once the size increases enough to fall out of the cache
25 into memory, the rate falls by about a factor of 3.
26*/
sewardj443cd9d2004-07-18 23:06:45 +000027#define N_TEMPORARY_BYTES 50000
sewardj35421a32004-07-05 13:12:34 +000028
sewardj443cd9d2004-07-18 23:06:45 +000029static Char temporary[N_TEMPORARY_BYTES];
30static Int temporary_used = 0;
31
32#define N_PERMANENT_BYTES 1000
33
34static Char permanent[N_TEMPORARY_BYTES];
35static Int permanent_used = 0;
36
sewardj35421a32004-07-05 13:12:34 +000037
sewardjce605f92004-07-05 14:39:15 +000038/* Gather statistics. */
sewardj443cd9d2004-07-18 23:06:45 +000039static Int temporary_bytes_allocd = 0;
40static Int temporary_count_allocs = 0;
sewardjce605f92004-07-05 14:39:15 +000041
sewardj443cd9d2004-07-18 23:06:45 +000042static ULong temporary_bytes_allocd_TOT = 0;
43static ULong temporary_count_allocs_TOT = 0;
44
45/* The current allocation mode. */
46static AllocMode mode = AllocModeTEMPORARY;
sewardjce605f92004-07-05 14:39:15 +000047
48
sewardj443cd9d2004-07-18 23:06:45 +000049/* Exported to library client. */
50
51void LibVEX_SetAllocMode ( AllocMode m )
52{
53 mode = m;
54}
55
56/* Exported to library client. */
57
58AllocMode LibVEX_GetAllocMode ( void )
59{
60 return mode;
61}
sewardjce605f92004-07-05 14:39:15 +000062
sewardj35421a32004-07-05 13:12:34 +000063/* Exported to library client. */
64
65void* LibVEX_Alloc ( Int nbytes )
66{
67 vassert(vex_initdone);
sewardj35439212004-07-14 22:36:10 +000068 vassert(nbytes >= 0);
sewardjd733aed2004-07-07 12:00:42 +000069 if (vex_valgrind_support) {
70 /* ugly hack */
71 extern void* malloc ( int );
72 return malloc(nbytes);
73 } else {
sewardj35439212004-07-14 22:36:10 +000074 if (nbytes == 0) nbytes = 8;
sewardjd733aed2004-07-07 12:00:42 +000075 nbytes = (nbytes + 7) & ~7;
sewardj443cd9d2004-07-18 23:06:45 +000076 if (mode == AllocModeTEMPORARY) {
77 if (temporary_used + nbytes > N_TEMPORARY_BYTES)
78 vpanic("VEX temporary storage exhausted.\n"
79 "Increase N_TEMPORARY_BYTES and recompile.");
80 temporary_count_allocs++;
81 temporary_bytes_allocd += nbytes;
82 temporary_used += nbytes;
83 return (void*)(&temporary[temporary_used - nbytes]);
84 } else {
85 if (permanent_used + nbytes > N_PERMANENT_BYTES)
86 vpanic("VEX permanent storage exhausted.\n"
87 "Increase N_PERMANENT_BYTES and recompile.");
88 permanent_used += nbytes;
89 return (void*)(&permanent[permanent_used - nbytes]);
90 }
sewardjd733aed2004-07-07 12:00:42 +000091 }
sewardj35421a32004-07-05 13:12:34 +000092}
93
94/* Exported to library client. */
95
sewardj443cd9d2004-07-18 23:06:45 +000096void LibVEX_ClearTemporary ( Bool verb )
sewardj35421a32004-07-05 13:12:34 +000097{
98 vassert(vex_initdone);
sewardj443cd9d2004-07-18 23:06:45 +000099 temporary_bytes_allocd_TOT += (ULong)temporary_bytes_allocd;
100 temporary_count_allocs_TOT += (ULong)temporary_count_allocs;
sewardjce605f92004-07-05 14:39:15 +0000101 if (verb) {
sewardj443cd9d2004-07-18 23:06:45 +0000102 vex_printf("vex storage: P %d, T total %lld (%lld), T curr %d (%d)\n",
103 permanent_used,
104 (Long)temporary_bytes_allocd_TOT,
105 (Long)temporary_count_allocs_TOT,
106 temporary_bytes_allocd, temporary_count_allocs );
sewardjce605f92004-07-05 14:39:15 +0000107 }
sewardj443cd9d2004-07-18 23:06:45 +0000108 temporary_used = 0;
109 temporary_bytes_allocd = 0;
110 temporary_count_allocs = 0;
sewardj35421a32004-07-05 13:12:34 +0000111}
112
113
114
115/*---------------------------------------------------------*/
116/*--- Bombing out ---*/
117/*---------------------------------------------------------*/
118
119__attribute__ ((noreturn))
120void vex_assert_fail ( const Char* expr,
121 const Char* file, Int line, const Char* fn )
122{
123 vex_printf( "\nvex: %s:%d (%s): Assertion `%s' failed.\n",
124 file, line, fn, expr );
125 (*vex_failure_exit)();
126}
127
128__attribute__ ((noreturn))
sewardjce605f92004-07-05 14:39:15 +0000129void vpanic ( Char* str )
sewardj35421a32004-07-05 13:12:34 +0000130{
131 vex_printf("\nvex: the `impossible' happened:\n %s\n", str);
132 (*vex_failure_exit)();
133}
134
135
136/*---------------------------------------------------------*/
137/*--- vex_printf ---*/
138/*---------------------------------------------------------*/
139
140/* This should be the only <...> include in the entire VEX library.
141 New code for vex_util.c should go above this point. */
142#include <stdarg.h>
143
144/* ---------------------------------------------------------------------
145 printf implementation. The key function, vg_vprintf(), emits chars
146 into a caller-supplied function. Distantly derived from:
147
148 vprintf replacement for Checker.
149 Copyright 1993, 1994, 1995 Tristan Gingold
150 Written September 1993 Tristan Gingold
151 Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE
152
153 (Checker itself was GPL'd.)
154 ------------------------------------------------------------------ */
155
156static Char vex_toupper ( Char c )
157{
158 if (c >= 'a' && c <= 'z')
159 return c + ('A' - 'a');
160 else
161 return c;
162}
163
164static Int vex_strlen ( const Char* str )
165{
166 Int i = 0;
167 while (str[i] != 0) i++;
168 return i;
169}
170
171
172/* Some flags. */
173#define VG_MSG_SIGNED 1 /* The value is signed. */
174#define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */
175#define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */
176#define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */
177#define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */
178
179/* Copy a string into the buffer. */
180static UInt
181myvprintf_str ( void(*send)(Char), Int flags, Int width, Char* str,
182 Bool capitalise )
183{
184# define MAYBE_TOUPPER(ch) (capitalise ? vex_toupper(ch) : (ch))
185 UInt ret = 0;
186 Int i, extra;
187 Int len = vex_strlen(str);
188
189 if (width == 0) {
190 ret += len;
191 for (i = 0; i < len; i++)
192 send(MAYBE_TOUPPER(str[i]));
193 return ret;
194 }
195
196 if (len > width) {
197 ret += width;
198 for (i = 0; i < width; i++)
199 send(MAYBE_TOUPPER(str[i]));
200 return ret;
201 }
202
203 extra = width - len;
204 if (flags & VG_MSG_LJUSTIFY) {
205 ret += extra;
206 for (i = 0; i < extra; i++)
207 send(' ');
208 }
209 ret += len;
210 for (i = 0; i < len; i++)
211 send(MAYBE_TOUPPER(str[i]));
212 if (!(flags & VG_MSG_LJUSTIFY)) {
213 ret += extra;
214 for (i = 0; i < extra; i++)
215 send(' ');
216 }
217
218# undef MAYBE_TOUPPER
219
220 return ret;
221}
222
223/* Write P into the buffer according to these args:
224 * If SIGN is true, p is a signed.
225 * BASE is the base.
226 * If WITH_ZERO is true, '0' must be added.
227 * WIDTH is the width of the field.
228 */
229static UInt
230myvprintf_int64 ( void(*send)(Char), Int flags, Int base, Int width, ULong p)
231{
232 Char buf[40];
233 Int ind = 0;
234 Int i, nc = 0;
235 Bool neg = False;
236 Char *digits = "0123456789ABCDEF";
237 UInt ret = 0;
238
239 if (base < 2 || base > 16)
240 return ret;
241
242 if ((flags & VG_MSG_SIGNED) && (Long)p < 0) {
243 p = - (Long)p;
244 neg = True;
245 }
246
247 if (p == 0)
248 buf[ind++] = '0';
249 else {
250 while (p > 0) {
251 if (flags & VG_MSG_COMMA && 10 == base &&
252 0 == (ind-nc) % 3 && 0 != ind)
253 {
254 buf[ind++] = ',';
255 nc++;
256 }
257 buf[ind++] = digits[p % base];
258 p /= base;
259 }
260 }
261
262 if (neg)
263 buf[ind++] = '-';
264
265 if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) {
266 for(; ind < width; ind++) {
267 vassert(ind < 39);
268 buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' ';
269 }
270 }
271
272 /* Reverse copy to buffer. */
273 ret += ind;
274 for (i = ind -1; i >= 0; i--) {
275 send(buf[i]);
276 }
277 if (width > 0 && (flags & VG_MSG_LJUSTIFY)) {
278 for(; ind < width; ind++) {
279 ret++;
280 send(' '); // Never pad with zeroes on RHS -- changes the value!
281 }
282 }
283 return ret;
284}
285
286
287/* A simple vprintf(). */
288static
289UInt vprintf_wrk ( void(*send)(Char), const Char *format, va_list vargs )
290{
291 UInt ret = 0;
292 int i;
293 int flags;
294 int width;
295 Bool is_long;
296
297 /* We assume that vargs has already been initialised by the
298 caller, using va_start, and that the caller will similarly
299 clean up with va_end.
300 */
301
302 for (i = 0; format[i] != 0; i++) {
303 if (format[i] != '%') {
304 send(format[i]);
305 ret++;
306 continue;
307 }
308 i++;
309 /* A '%' has been found. Ignore a trailing %. */
310 if (format[i] == 0)
311 break;
312 if (format[i] == '%') {
313 /* `%%' is replaced by `%'. */
314 send('%');
315 ret++;
316 continue;
317 }
318 flags = 0;
319 is_long = False;
320 width = 0; /* length of the field. */
321 if (format[i] == '(') {
322 flags |= VG_MSG_PAREN;
323 i++;
324 }
325 /* If ',' follows '%', commas will be inserted. */
326 if (format[i] == ',') {
327 flags |= VG_MSG_COMMA;
328 i++;
329 }
330 /* If '-' follows '%', justify on the left. */
331 if (format[i] == '-') {
332 flags |= VG_MSG_LJUSTIFY;
333 i++;
334 }
335 /* If '0' follows '%', pads will be inserted. */
336 if (format[i] == '0') {
337 flags |= VG_MSG_ZJUSTIFY;
338 i++;
339 }
340 /* Compute the field length. */
341 while (format[i] >= '0' && format[i] <= '9') {
342 width *= 10;
343 width += format[i++] - '0';
344 }
345 while (format[i] == 'l') {
346 i++;
347 is_long = True;
348 }
349
350 switch (format[i]) {
351 case 'd': /* %d */
352 flags |= VG_MSG_SIGNED;
353 if (is_long)
354 ret += myvprintf_int64(send, flags, 10, width,
355 (ULong)(va_arg (vargs, Long)));
356 else
357 ret += myvprintf_int64(send, flags, 10, width,
358 (ULong)(va_arg (vargs, Int)));
359 break;
360 case 'u': /* %u */
361 if (is_long)
362 ret += myvprintf_int64(send, flags, 10, width,
363 (ULong)(va_arg (vargs, ULong)));
364 else
365 ret += myvprintf_int64(send, flags, 10, width,
366 (ULong)(va_arg (vargs, UInt)));
367 break;
368 case 'p': /* %p */
369 ret += 2;
370 send('0');
371 send('x');
372 ret += myvprintf_int64(send, flags, 16, width,
373 (ULong)((UInt)va_arg (vargs, void *)));
374 break;
375 case 'x': /* %x */
376 if (is_long)
377 ret += myvprintf_int64(send, flags, 16, width,
378 (ULong)(va_arg (vargs, ULong)));
379 else
380 ret += myvprintf_int64(send, flags, 16, width,
381 (ULong)(va_arg (vargs, UInt)));
382 break;
383 case 'c': /* %c */
384 ret++;
385 send(va_arg (vargs, int));
386 break;
387 case 's': case 'S': { /* %s */
388 char *str = va_arg (vargs, char *);
389 if (str == (char*) 0) str = "(null)";
390 ret += myvprintf_str(send, flags, width, str, format[i]=='S');
391 break;
392 }
393# if 0
394 case 'y': { /* %y - print symbol */
395 Char buf[100];
396 Char *cp = buf;
397 Addr a = va_arg(vargs, Addr);
398
399 if (flags & VG_MSG_PAREN)
400 *cp++ = '(';
401 if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) {
402 if (flags & VG_MSG_PAREN) {
403 cp += VG_(strlen)(cp);
404 *cp++ = ')';
405 *cp = '\0';
406 }
407 ret += myvprintf_str(send, flags, width, buf, 0);
408 }
409 break;
410 }
411# endif
412 default:
413 break;
414 }
415 }
416 return ret;
417}
418
419
420/* A general replacement for printf(). Note that only low-level
421 debugging info should be sent via here. The official route is to
422 to use vg_message(). This interface is deprecated.
423*/
424static Char myprintf_buf[1000];
425static Int n_myprintf_buf;
426
427static void add_to_myprintf_buf ( Char c )
428{
429 if (c == '\n' || n_myprintf_buf >= 1000-10 /*paranoia*/ ) {
430 (*vex_log_bytes)( myprintf_buf, vex_strlen(myprintf_buf) );
431 n_myprintf_buf = 0;
432 myprintf_buf[n_myprintf_buf] = 0;
433 }
434 myprintf_buf[n_myprintf_buf++] = c;
435 myprintf_buf[n_myprintf_buf] = 0;
436}
437
438UInt vex_printf ( const char *format, ... )
439{
440 UInt ret;
441 va_list vargs;
442 va_start(vargs,format);
443
444 n_myprintf_buf = 0;
445 myprintf_buf[n_myprintf_buf] = 0;
446 ret = vprintf_wrk ( add_to_myprintf_buf, format, vargs );
447
448 if (n_myprintf_buf > 0) {
449 (*vex_log_bytes)( myprintf_buf, n_myprintf_buf );
450 }
451
452 va_end(vargs);
453
454 return ret;
455}
456
457
sewardj41f43bc2004-07-08 14:23:22 +0000458/* A general replacement for sprintf(). */
459
460static Char *vg_sprintf_ptr;
461
462static void add_to_vg_sprintf_buf ( Char c )
463{
464 *vg_sprintf_ptr++ = c;
465}
466
467UInt vex_sprintf ( Char* buf, const Char *format, ... )
468{
469 Int ret;
470 va_list vargs;
471
472 vg_sprintf_ptr = buf;
473
474 va_start(vargs,format);
475
476 ret = vprintf_wrk ( add_to_vg_sprintf_buf, format, vargs );
477 add_to_vg_sprintf_buf(0);
478
479 va_end(vargs);
480
481 vassert(vex_strlen(buf) == ret);
482 return ret;
483}
484
485
486
487
sewardj35421a32004-07-05 13:12:34 +0000488/*---------------------------------------------------------------*/
489/*--- end vex_util.c ---*/
490/*---------------------------------------------------------------*/