| |
| /*---------------------------------------------------------------*/ |
| /*--- ---*/ |
| /*--- This file (vex_util.c) is ---*/ |
| /*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/ |
| /*--- ---*/ |
| /*---------------------------------------------------------------*/ |
| |
| #include "libvex_basictypes.h" |
| #include "libvex.h" |
| |
| #include "vex_globals.h" |
| #include "vex_util.h" |
| |
| |
| /*---------------------------------------------------------*/ |
| /*--- Storage ---*/ |
| /*---------------------------------------------------------*/ |
| |
| /* Try to keep this as low as possible -- in particular, less than the |
| size of the smallest L2 cache we might encounter. At 50000, my VIA |
| Nehemiah 1 GHz (a weedy machine) can satisfy 27 million calls/ |
| second to LibVEX_Alloc(16) -- that is, allocate memory at over 400 |
| MByte/sec. Once the size increases enough to fall out of the cache |
| into memory, the rate falls by about a factor of 3. |
| */ |
| #define N_STORAGE_BYTES 50000 |
| |
| static Char storage[N_STORAGE_BYTES]; |
| static Int storage_used = 0; |
| |
| /* Gather statistics. */ |
| static Int storage_bytes_allocd = 0; |
| static Int storage_count_allocs = 0; |
| |
| static ULong storage_bytes_allocd_TOT = 0; |
| static ULong storage_count_allocs_TOT = 0; |
| |
| |
| |
| /* Exported to library client. */ |
| |
| void* LibVEX_Alloc ( Int nbytes ) |
| { |
| vassert(vex_initdone); |
| vassert(nbytes > 0); |
| if (vex_valgrind_support) { |
| /* ugly hack */ |
| extern void* malloc ( int ); |
| return malloc(nbytes); |
| } else { |
| nbytes = (nbytes + 7) & ~7; |
| if (storage_used + nbytes > N_STORAGE_BYTES) |
| vpanic("VEX storage exhausted.\n" |
| "Increase N_STORAGE_BYTES and recompile."); |
| storage_count_allocs++; |
| storage_bytes_allocd += nbytes; |
| storage_used += nbytes; |
| return (void*)(&storage[storage_used - nbytes]); |
| } |
| } |
| |
| /* Exported to library client. */ |
| |
| void LibVEX_Clear ( Bool verb ) |
| { |
| vassert(vex_initdone); |
| storage_bytes_allocd_TOT += (ULong)storage_bytes_allocd; |
| storage_count_allocs_TOT += (ULong)storage_count_allocs; |
| if (verb) { |
| vex_printf("vex storage: total %lld (%lld), curr %d (%d)\n", |
| (Long)storage_bytes_allocd_TOT, |
| (Long)storage_count_allocs_TOT, |
| storage_bytes_allocd, storage_count_allocs ); |
| } |
| storage_used = 0; |
| storage_bytes_allocd = 0; |
| storage_count_allocs = 0; |
| } |
| |
| |
| |
| /*---------------------------------------------------------*/ |
| /*--- Bombing out ---*/ |
| /*---------------------------------------------------------*/ |
| |
| __attribute__ ((noreturn)) |
| void vex_assert_fail ( const Char* expr, |
| const Char* file, Int line, const Char* fn ) |
| { |
| vex_printf( "\nvex: %s:%d (%s): Assertion `%s' failed.\n", |
| file, line, fn, expr ); |
| (*vex_failure_exit)(); |
| } |
| |
| __attribute__ ((noreturn)) |
| void vpanic ( Char* str ) |
| { |
| vex_printf("\nvex: the `impossible' happened:\n %s\n", str); |
| (*vex_failure_exit)(); |
| } |
| |
| |
| /*---------------------------------------------------------*/ |
| /*--- vex_printf ---*/ |
| /*---------------------------------------------------------*/ |
| |
| /* This should be the only <...> include in the entire VEX library. |
| New code for vex_util.c should go above this point. */ |
| #include <stdarg.h> |
| |
| /* --------------------------------------------------------------------- |
| printf implementation. The key function, vg_vprintf(), emits chars |
| into a caller-supplied function. Distantly derived from: |
| |
| vprintf replacement for Checker. |
| Copyright 1993, 1994, 1995 Tristan Gingold |
| Written September 1993 Tristan Gingold |
| Tristan Gingold, 8 rue Parmentier, F-91120 PALAISEAU, FRANCE |
| |
| (Checker itself was GPL'd.) |
| ------------------------------------------------------------------ */ |
| |
| static Char vex_toupper ( Char c ) |
| { |
| if (c >= 'a' && c <= 'z') |
| return c + ('A' - 'a'); |
| else |
| return c; |
| } |
| |
| static Int vex_strlen ( const Char* str ) |
| { |
| Int i = 0; |
| while (str[i] != 0) i++; |
| return i; |
| } |
| |
| |
| /* Some flags. */ |
| #define VG_MSG_SIGNED 1 /* The value is signed. */ |
| #define VG_MSG_ZJUSTIFY 2 /* Must justify with '0'. */ |
| #define VG_MSG_LJUSTIFY 4 /* Must justify on the left. */ |
| #define VG_MSG_PAREN 8 /* Parenthesize if present (for %y) */ |
| #define VG_MSG_COMMA 16 /* Add commas to numbers (for %d, %u) */ |
| |
| /* Copy a string into the buffer. */ |
| static UInt |
| myvprintf_str ( void(*send)(Char), Int flags, Int width, Char* str, |
| Bool capitalise ) |
| { |
| # define MAYBE_TOUPPER(ch) (capitalise ? vex_toupper(ch) : (ch)) |
| UInt ret = 0; |
| Int i, extra; |
| Int len = vex_strlen(str); |
| |
| if (width == 0) { |
| ret += len; |
| for (i = 0; i < len; i++) |
| send(MAYBE_TOUPPER(str[i])); |
| return ret; |
| } |
| |
| if (len > width) { |
| ret += width; |
| for (i = 0; i < width; i++) |
| send(MAYBE_TOUPPER(str[i])); |
| return ret; |
| } |
| |
| extra = width - len; |
| if (flags & VG_MSG_LJUSTIFY) { |
| ret += extra; |
| for (i = 0; i < extra; i++) |
| send(' '); |
| } |
| ret += len; |
| for (i = 0; i < len; i++) |
| send(MAYBE_TOUPPER(str[i])); |
| if (!(flags & VG_MSG_LJUSTIFY)) { |
| ret += extra; |
| for (i = 0; i < extra; i++) |
| send(' '); |
| } |
| |
| # undef MAYBE_TOUPPER |
| |
| return ret; |
| } |
| |
| /* Write P into the buffer according to these args: |
| * If SIGN is true, p is a signed. |
| * BASE is the base. |
| * If WITH_ZERO is true, '0' must be added. |
| * WIDTH is the width of the field. |
| */ |
| static UInt |
| myvprintf_int64 ( void(*send)(Char), Int flags, Int base, Int width, ULong p) |
| { |
| Char buf[40]; |
| Int ind = 0; |
| Int i, nc = 0; |
| Bool neg = False; |
| Char *digits = "0123456789ABCDEF"; |
| UInt ret = 0; |
| |
| if (base < 2 || base > 16) |
| return ret; |
| |
| if ((flags & VG_MSG_SIGNED) && (Long)p < 0) { |
| p = - (Long)p; |
| neg = True; |
| } |
| |
| if (p == 0) |
| buf[ind++] = '0'; |
| else { |
| while (p > 0) { |
| if (flags & VG_MSG_COMMA && 10 == base && |
| 0 == (ind-nc) % 3 && 0 != ind) |
| { |
| buf[ind++] = ','; |
| nc++; |
| } |
| buf[ind++] = digits[p % base]; |
| p /= base; |
| } |
| } |
| |
| if (neg) |
| buf[ind++] = '-'; |
| |
| if (width > 0 && !(flags & VG_MSG_LJUSTIFY)) { |
| for(; ind < width; ind++) { |
| vassert(ind < 39); |
| buf[ind] = (flags & VG_MSG_ZJUSTIFY) ? '0': ' '; |
| } |
| } |
| |
| /* Reverse copy to buffer. */ |
| ret += ind; |
| for (i = ind -1; i >= 0; i--) { |
| send(buf[i]); |
| } |
| if (width > 0 && (flags & VG_MSG_LJUSTIFY)) { |
| for(; ind < width; ind++) { |
| ret++; |
| send(' '); // Never pad with zeroes on RHS -- changes the value! |
| } |
| } |
| return ret; |
| } |
| |
| |
| /* A simple vprintf(). */ |
| static |
| UInt vprintf_wrk ( void(*send)(Char), const Char *format, va_list vargs ) |
| { |
| UInt ret = 0; |
| int i; |
| int flags; |
| int width; |
| Bool is_long; |
| |
| /* We assume that vargs has already been initialised by the |
| caller, using va_start, and that the caller will similarly |
| clean up with va_end. |
| */ |
| |
| for (i = 0; format[i] != 0; i++) { |
| if (format[i] != '%') { |
| send(format[i]); |
| ret++; |
| continue; |
| } |
| i++; |
| /* A '%' has been found. Ignore a trailing %. */ |
| if (format[i] == 0) |
| break; |
| if (format[i] == '%') { |
| /* `%%' is replaced by `%'. */ |
| send('%'); |
| ret++; |
| continue; |
| } |
| flags = 0; |
| is_long = False; |
| width = 0; /* length of the field. */ |
| if (format[i] == '(') { |
| flags |= VG_MSG_PAREN; |
| i++; |
| } |
| /* If ',' follows '%', commas will be inserted. */ |
| if (format[i] == ',') { |
| flags |= VG_MSG_COMMA; |
| i++; |
| } |
| /* If '-' follows '%', justify on the left. */ |
| if (format[i] == '-') { |
| flags |= VG_MSG_LJUSTIFY; |
| i++; |
| } |
| /* If '0' follows '%', pads will be inserted. */ |
| if (format[i] == '0') { |
| flags |= VG_MSG_ZJUSTIFY; |
| i++; |
| } |
| /* Compute the field length. */ |
| while (format[i] >= '0' && format[i] <= '9') { |
| width *= 10; |
| width += format[i++] - '0'; |
| } |
| while (format[i] == 'l') { |
| i++; |
| is_long = True; |
| } |
| |
| switch (format[i]) { |
| case 'd': /* %d */ |
| flags |= VG_MSG_SIGNED; |
| if (is_long) |
| ret += myvprintf_int64(send, flags, 10, width, |
| (ULong)(va_arg (vargs, Long))); |
| else |
| ret += myvprintf_int64(send, flags, 10, width, |
| (ULong)(va_arg (vargs, Int))); |
| break; |
| case 'u': /* %u */ |
| if (is_long) |
| ret += myvprintf_int64(send, flags, 10, width, |
| (ULong)(va_arg (vargs, ULong))); |
| else |
| ret += myvprintf_int64(send, flags, 10, width, |
| (ULong)(va_arg (vargs, UInt))); |
| break; |
| case 'p': /* %p */ |
| ret += 2; |
| send('0'); |
| send('x'); |
| ret += myvprintf_int64(send, flags, 16, width, |
| (ULong)((UInt)va_arg (vargs, void *))); |
| break; |
| case 'x': /* %x */ |
| if (is_long) |
| ret += myvprintf_int64(send, flags, 16, width, |
| (ULong)(va_arg (vargs, ULong))); |
| else |
| ret += myvprintf_int64(send, flags, 16, width, |
| (ULong)(va_arg (vargs, UInt))); |
| break; |
| case 'c': /* %c */ |
| ret++; |
| send(va_arg (vargs, int)); |
| break; |
| case 's': case 'S': { /* %s */ |
| char *str = va_arg (vargs, char *); |
| if (str == (char*) 0) str = "(null)"; |
| ret += myvprintf_str(send, flags, width, str, format[i]=='S'); |
| break; |
| } |
| # if 0 |
| case 'y': { /* %y - print symbol */ |
| Char buf[100]; |
| Char *cp = buf; |
| Addr a = va_arg(vargs, Addr); |
| |
| if (flags & VG_MSG_PAREN) |
| *cp++ = '('; |
| if (VG_(get_fnname_w_offset)(a, cp, sizeof(buf)-4)) { |
| if (flags & VG_MSG_PAREN) { |
| cp += VG_(strlen)(cp); |
| *cp++ = ')'; |
| *cp = '\0'; |
| } |
| ret += myvprintf_str(send, flags, width, buf, 0); |
| } |
| break; |
| } |
| # endif |
| default: |
| break; |
| } |
| } |
| return ret; |
| } |
| |
| |
| /* A general replacement for printf(). Note that only low-level |
| debugging info should be sent via here. The official route is to |
| to use vg_message(). This interface is deprecated. |
| */ |
| static Char myprintf_buf[1000]; |
| static Int n_myprintf_buf; |
| |
| static void add_to_myprintf_buf ( Char c ) |
| { |
| if (c == '\n' || n_myprintf_buf >= 1000-10 /*paranoia*/ ) { |
| (*vex_log_bytes)( myprintf_buf, vex_strlen(myprintf_buf) ); |
| n_myprintf_buf = 0; |
| myprintf_buf[n_myprintf_buf] = 0; |
| } |
| myprintf_buf[n_myprintf_buf++] = c; |
| myprintf_buf[n_myprintf_buf] = 0; |
| } |
| |
| UInt vex_printf ( const char *format, ... ) |
| { |
| UInt ret; |
| va_list vargs; |
| va_start(vargs,format); |
| |
| n_myprintf_buf = 0; |
| myprintf_buf[n_myprintf_buf] = 0; |
| ret = vprintf_wrk ( add_to_myprintf_buf, format, vargs ); |
| |
| if (n_myprintf_buf > 0) { |
| (*vex_log_bytes)( myprintf_buf, n_myprintf_buf ); |
| } |
| |
| va_end(vargs); |
| |
| return ret; |
| } |
| |
| |
| /* A general replacement for sprintf(). */ |
| |
| static Char *vg_sprintf_ptr; |
| |
| static void add_to_vg_sprintf_buf ( Char c ) |
| { |
| *vg_sprintf_ptr++ = c; |
| } |
| |
| UInt vex_sprintf ( Char* buf, const Char *format, ... ) |
| { |
| Int ret; |
| va_list vargs; |
| |
| vg_sprintf_ptr = buf; |
| |
| va_start(vargs,format); |
| |
| ret = vprintf_wrk ( add_to_vg_sprintf_buf, format, vargs ); |
| add_to_vg_sprintf_buf(0); |
| |
| va_end(vargs); |
| |
| vassert(vex_strlen(buf) == ret); |
| return ret; |
| } |
| |
| |
| |
| |
| /*---------------------------------------------------------------*/ |
| /*--- end vex_util.c ---*/ |
| /*---------------------------------------------------------------*/ |