sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 1 | |
| 2 | /*---------------------------------------------------------------*/ |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 3 | /*--- begin main_util.c ---*/ |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 4 | /*---------------------------------------------------------------*/ |
| 5 | |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 6 | /* |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 7 | This file is part of Valgrind, a dynamic binary instrumentation |
| 8 | framework. |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 9 | |
sewardj | 89ae847 | 2013-10-18 14:12:58 +0000 | [diff] [blame] | 10 | Copyright (C) 2004-2013 OpenWorks LLP |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 11 | info@open-works.net |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 12 | |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 13 | This program is free software; you can redistribute it and/or |
| 14 | modify it under the terms of the GNU General Public License as |
| 15 | published by the Free Software Foundation; either version 2 of the |
| 16 | License, or (at your option) any later version. |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 17 | |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 18 | This program is distributed in the hope that it will be useful, but |
| 19 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 21 | General Public License for more details. |
| 22 | |
| 23 | You should have received a copy of the GNU General Public License |
| 24 | along with this program; if not, write to the Free Software |
| 25 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
sewardj | 7bd6ffe | 2005-08-03 16:07:36 +0000 | [diff] [blame] | 26 | 02110-1301, USA. |
| 27 | |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 28 | The GNU General Public License is contained in the file COPYING. |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 29 | |
| 30 | Neither the names of the U.S. Department of Energy nor the |
| 31 | University of California nor the names of its contributors may be |
| 32 | used to endorse or promote products derived from this software |
| 33 | without prior written permission. |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 34 | */ |
| 35 | |
sewardj | 887a11a | 2004-07-05 17:26:47 +0000 | [diff] [blame] | 36 | #include "libvex_basictypes.h" |
sewardj | 41f43bc | 2004-07-08 14:23:22 +0000 | [diff] [blame] | 37 | #include "libvex.h" |
| 38 | |
sewardj | cef7d3e | 2009-07-02 12:21:59 +0000 | [diff] [blame] | 39 | #include "main_globals.h" |
| 40 | #include "main_util.h" |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 41 | |
| 42 | |
| 43 | /*---------------------------------------------------------*/ |
| 44 | /*--- Storage ---*/ |
| 45 | /*---------------------------------------------------------*/ |
| 46 | |
sewardj | ce605f9 | 2004-07-05 14:39:15 +0000 | [diff] [blame] | 47 | /* Try to keep this as low as possible -- in particular, less than the |
| 48 | size of the smallest L2 cache we might encounter. At 50000, my VIA |
| 49 | Nehemiah 1 GHz (a weedy machine) can satisfy 27 million calls/ |
| 50 | second to LibVEX_Alloc(16) -- that is, allocate memory at over 400 |
| 51 | MByte/sec. Once the size increases enough to fall out of the cache |
| 52 | into memory, the rate falls by about a factor of 3. |
| 53 | */ |
sewardj | e165a8a | 2010-09-29 21:39:12 +0000 | [diff] [blame] | 54 | #define N_TEMPORARY_BYTES 5000000 |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 55 | |
sewardj | 4eeda9c | 2005-11-25 02:47:00 +0000 | [diff] [blame] | 56 | static HChar temporary[N_TEMPORARY_BYTES] __attribute__((aligned(8))); |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 57 | static HChar* temporary_first = &temporary[0]; |
| 58 | static HChar* temporary_curr = &temporary[0]; |
| 59 | static HChar* temporary_last = &temporary[N_TEMPORARY_BYTES-1]; |
| 60 | |
| 61 | static ULong temporary_bytes_allocd_TOT = 0; |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 62 | |
sewardj | e29a31d | 2007-05-05 12:26:23 +0000 | [diff] [blame] | 63 | #define N_PERMANENT_BYTES 10000 |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 64 | |
sewardj | e29a31d | 2007-05-05 12:26:23 +0000 | [diff] [blame] | 65 | static HChar permanent[N_PERMANENT_BYTES] __attribute__((aligned(8))); |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 66 | static HChar* permanent_first = &permanent[0]; |
| 67 | static HChar* permanent_curr = &permanent[0]; |
sewardj | e29a31d | 2007-05-05 12:26:23 +0000 | [diff] [blame] | 68 | static HChar* permanent_last = &permanent[N_PERMANENT_BYTES-1]; |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 69 | |
florian | bde3406 | 2014-10-11 14:48:38 +0000 | [diff] [blame] | 70 | static HChar* private_LibVEX_alloc_first = &temporary[0]; |
| 71 | static HChar* private_LibVEX_alloc_curr = &temporary[0]; |
| 72 | static HChar* private_LibVEX_alloc_last = &temporary[N_TEMPORARY_BYTES-1]; |
| 73 | |
| 74 | |
sewardj | d887b86 | 2005-01-17 18:34:34 +0000 | [diff] [blame] | 75 | static VexAllocMode mode = VexAllocModeTEMP; |
sewardj | ce605f9 | 2004-07-05 14:39:15 +0000 | [diff] [blame] | 76 | |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 77 | void vexAllocSanityCheck ( void ) |
| 78 | { |
| 79 | vassert(temporary_first == &temporary[0]); |
| 80 | vassert(temporary_last == &temporary[N_TEMPORARY_BYTES-1]); |
| 81 | vassert(permanent_first == &permanent[0]); |
sewardj | e29a31d | 2007-05-05 12:26:23 +0000 | [diff] [blame] | 82 | vassert(permanent_last == &permanent[N_PERMANENT_BYTES-1]); |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 83 | vassert(temporary_first <= temporary_curr); |
| 84 | vassert(temporary_curr <= temporary_last); |
| 85 | vassert(permanent_first <= permanent_curr); |
| 86 | vassert(permanent_curr <= permanent_last); |
| 87 | vassert(private_LibVEX_alloc_first <= private_LibVEX_alloc_curr); |
| 88 | vassert(private_LibVEX_alloc_curr <= private_LibVEX_alloc_last); |
| 89 | if (mode == VexAllocModeTEMP){ |
| 90 | vassert(private_LibVEX_alloc_first == temporary_first); |
| 91 | vassert(private_LibVEX_alloc_last == temporary_last); |
| 92 | } |
| 93 | else |
| 94 | if (mode == VexAllocModePERM) { |
| 95 | vassert(private_LibVEX_alloc_first == permanent_first); |
| 96 | vassert(private_LibVEX_alloc_last == permanent_last); |
| 97 | } |
| 98 | else |
| 99 | vassert(0); |
| 100 | |
| 101 | # define IS_WORD_ALIGNED(p) (0 == (((HWord)p) & (sizeof(HWord)-1))) |
| 102 | vassert(sizeof(HWord) == 4 || sizeof(HWord) == 8); |
| 103 | vassert(IS_WORD_ALIGNED(temporary_first)); |
| 104 | vassert(IS_WORD_ALIGNED(temporary_curr)); |
| 105 | vassert(IS_WORD_ALIGNED(temporary_last+1)); |
| 106 | vassert(IS_WORD_ALIGNED(permanent_first)); |
| 107 | vassert(IS_WORD_ALIGNED(permanent_curr)); |
| 108 | vassert(IS_WORD_ALIGNED(permanent_last+1)); |
| 109 | vassert(IS_WORD_ALIGNED(private_LibVEX_alloc_first)); |
| 110 | vassert(IS_WORD_ALIGNED(private_LibVEX_alloc_curr)); |
| 111 | vassert(IS_WORD_ALIGNED(private_LibVEX_alloc_last+1)); |
| 112 | # undef IS_WORD_ALIGNED |
| 113 | } |
| 114 | |
| 115 | /* The current allocation mode. */ |
sewardj | ce605f9 | 2004-07-05 14:39:15 +0000 | [diff] [blame] | 116 | |
sewardj | d887b86 | 2005-01-17 18:34:34 +0000 | [diff] [blame] | 117 | void vexSetAllocMode ( VexAllocMode m ) |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 118 | { |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 119 | vexAllocSanityCheck(); |
| 120 | |
| 121 | /* Save away the current allocation point .. */ |
| 122 | if (mode == VexAllocModeTEMP){ |
| 123 | temporary_curr = private_LibVEX_alloc_curr; |
| 124 | } |
| 125 | else |
| 126 | if (mode == VexAllocModePERM) { |
| 127 | permanent_curr = private_LibVEX_alloc_curr; |
| 128 | } |
| 129 | else |
| 130 | vassert(0); |
| 131 | |
| 132 | /* Did that screw anything up? */ |
| 133 | vexAllocSanityCheck(); |
| 134 | |
| 135 | if (m == VexAllocModeTEMP){ |
| 136 | private_LibVEX_alloc_first = temporary_first; |
| 137 | private_LibVEX_alloc_curr = temporary_curr; |
| 138 | private_LibVEX_alloc_last = temporary_last; |
| 139 | } |
| 140 | else |
| 141 | if (m == VexAllocModePERM) { |
| 142 | private_LibVEX_alloc_first = permanent_first; |
| 143 | private_LibVEX_alloc_curr = permanent_curr; |
| 144 | private_LibVEX_alloc_last = permanent_last; |
| 145 | } |
| 146 | else |
| 147 | vassert(0); |
| 148 | |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 149 | mode = m; |
| 150 | } |
| 151 | |
sewardj | d887b86 | 2005-01-17 18:34:34 +0000 | [diff] [blame] | 152 | VexAllocMode vexGetAllocMode ( void ) |
sewardj | 443cd9d | 2004-07-18 23:06:45 +0000 | [diff] [blame] | 153 | { |
| 154 | return mode; |
| 155 | } |
sewardj | ce605f9 | 2004-07-05 14:39:15 +0000 | [diff] [blame] | 156 | |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 157 | __attribute__((noreturn)) |
florian | bde3406 | 2014-10-11 14:48:38 +0000 | [diff] [blame] | 158 | static void private_LibVEX_alloc_OOM(void) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 159 | { |
florian | 55085f8 | 2012-11-21 00:36:55 +0000 | [diff] [blame] | 160 | const HChar* pool = "???"; |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 161 | if (private_LibVEX_alloc_first == &temporary[0]) pool = "TEMP"; |
| 162 | if (private_LibVEX_alloc_first == &permanent[0]) pool = "PERM"; |
| 163 | vex_printf("VEX temporary storage exhausted.\n"); |
sewardj | 66afb9f | 2005-11-25 04:28:46 +0000 | [diff] [blame] | 164 | vex_printf("Pool = %s, start %p curr %p end %p (size %lld)\n", |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 165 | pool, |
| 166 | private_LibVEX_alloc_first, |
| 167 | private_LibVEX_alloc_curr, |
| 168 | private_LibVEX_alloc_last, |
sewardj | e29a31d | 2007-05-05 12:26:23 +0000 | [diff] [blame] | 169 | (Long)(private_LibVEX_alloc_last + 1 - private_LibVEX_alloc_first)); |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 170 | vpanic("VEX temporary storage exhausted.\n" |
| 171 | "Increase N_{TEMPORARY,PERMANENT}_BYTES and recompile."); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 172 | } |
| 173 | |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 174 | void vexSetAllocModeTEMP_and_clear ( void ) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 175 | { |
sewardj | 7df596b | 2004-12-06 14:29:12 +0000 | [diff] [blame] | 176 | /* vassert(vex_initdone); */ /* causes infinite assert loops */ |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 177 | temporary_bytes_allocd_TOT |
sewardj | 66afb9f | 2005-11-25 04:28:46 +0000 | [diff] [blame] | 178 | += (ULong)(private_LibVEX_alloc_curr - private_LibVEX_alloc_first); |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 179 | |
| 180 | mode = VexAllocModeTEMP; |
| 181 | temporary_curr = &temporary[0]; |
| 182 | private_LibVEX_alloc_curr = &temporary[0]; |
sewardj | 8688a72 | 2009-12-03 09:50:38 +0000 | [diff] [blame] | 183 | |
| 184 | /* Set to (1) and change the fill byte to 0x00 or 0xFF to test for |
| 185 | any potential bugs due to using uninitialised memory in the main |
| 186 | VEX storage area. */ |
| 187 | if (0) { |
| 188 | Int i; |
| 189 | for (i = 0; i < N_TEMPORARY_BYTES; i++) |
| 190 | temporary[i] = 0x00; |
| 191 | } |
| 192 | |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 193 | vexAllocSanityCheck(); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 194 | } |
| 195 | |
| 196 | |
sewardj | d887b86 | 2005-01-17 18:34:34 +0000 | [diff] [blame] | 197 | /* Exported to library client. */ |
| 198 | |
florian | bde3406 | 2014-10-11 14:48:38 +0000 | [diff] [blame] | 199 | /* Allocate in Vex's temporary allocation area. Be careful with this. |
| 200 | You can only call it inside an instrumentation or optimisation |
| 201 | callback that you have previously specified in a call to |
| 202 | LibVEX_Translate. The storage allocated will only stay alive until |
| 203 | translation of the current basic block is complete. |
| 204 | */ |
| 205 | |
| 206 | void* LibVEX_Alloc ( Int nbytes ) |
| 207 | { |
| 208 | struct align { |
| 209 | char c; |
| 210 | union { |
| 211 | char c; |
| 212 | short s; |
| 213 | int i; |
| 214 | long l; |
| 215 | long long ll; |
| 216 | float f; |
| 217 | double d; |
| 218 | /* long double is currently not used and would increase alignment |
| 219 | unnecessarily. */ |
| 220 | /* long double ld; */ |
| 221 | void *pto; |
| 222 | void (*ptf)(void); |
| 223 | } x; |
| 224 | }; |
| 225 | |
| 226 | #if 0 |
| 227 | /* Nasty debugging hack, do not use. */ |
| 228 | return malloc(nbytes); |
| 229 | #else |
| 230 | HChar* curr; |
| 231 | HChar* next; |
| 232 | Int ALIGN; |
| 233 | ALIGN = offsetof(struct align,x) - 1; |
| 234 | nbytes = (nbytes + ALIGN) & ~ALIGN; |
| 235 | curr = private_LibVEX_alloc_curr; |
| 236 | next = curr + nbytes; |
| 237 | if (next >= private_LibVEX_alloc_last) |
| 238 | private_LibVEX_alloc_OOM(); |
| 239 | private_LibVEX_alloc_curr = next; |
| 240 | return curr; |
| 241 | #endif |
| 242 | } |
| 243 | |
sewardj | d887b86 | 2005-01-17 18:34:34 +0000 | [diff] [blame] | 244 | void LibVEX_ShowAllocStats ( void ) |
| 245 | { |
sewardj | 2d6b14a | 2005-11-23 04:25:07 +0000 | [diff] [blame] | 246 | vex_printf("vex storage: T total %lld bytes allocated\n", |
| 247 | (Long)temporary_bytes_allocd_TOT ); |
sewardj | e29a31d | 2007-05-05 12:26:23 +0000 | [diff] [blame] | 248 | vex_printf("vex storage: P total %lld bytes allocated\n", |
| 249 | (Long)(permanent_curr - permanent_first) ); |
sewardj | d887b86 | 2005-01-17 18:34:34 +0000 | [diff] [blame] | 250 | } |
| 251 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 252 | |
| 253 | /*---------------------------------------------------------*/ |
| 254 | /*--- Bombing out ---*/ |
| 255 | /*---------------------------------------------------------*/ |
| 256 | |
| 257 | __attribute__ ((noreturn)) |
sewardj | 5827784 | 2005-02-07 03:11:17 +0000 | [diff] [blame] | 258 | void vex_assert_fail ( const HChar* expr, |
| 259 | const HChar* file, Int line, const HChar* fn ) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 260 | { |
| 261 | vex_printf( "\nvex: %s:%d (%s): Assertion `%s' failed.\n", |
| 262 | file, line, fn, expr ); |
| 263 | (*vex_failure_exit)(); |
| 264 | } |
| 265 | |
| 266 | __attribute__ ((noreturn)) |
florian | 76714fd | 2012-09-13 20:21:42 +0000 | [diff] [blame] | 267 | void vpanic ( const HChar* str ) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 268 | { |
| 269 | vex_printf("\nvex: the `impossible' happened:\n %s\n", str); |
| 270 | (*vex_failure_exit)(); |
| 271 | } |
| 272 | |
| 273 | |
| 274 | /*---------------------------------------------------------*/ |
| 275 | /*--- vex_printf ---*/ |
| 276 | /*---------------------------------------------------------*/ |
| 277 | |
| 278 | /* This should be the only <...> include in the entire VEX library. |
| 279 | New code for vex_util.c should go above this point. */ |
| 280 | #include <stdarg.h> |
| 281 | |
sewardj | d7bde72 | 2011-04-05 13:19:33 +0000 | [diff] [blame] | 282 | Int vex_strlen ( const HChar* str ) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 283 | { |
| 284 | Int i = 0; |
| 285 | while (str[i] != 0) i++; |
| 286 | return i; |
| 287 | } |
| 288 | |
sewardj | 5827784 | 2005-02-07 03:11:17 +0000 | [diff] [blame] | 289 | Bool vex_streq ( const HChar* s1, const HChar* s2 ) |
sewardj | 36ca513 | 2004-07-24 13:12:23 +0000 | [diff] [blame] | 290 | { |
| 291 | while (True) { |
| 292 | if (*s1 == 0 && *s2 == 0) |
| 293 | return True; |
| 294 | if (*s1 != *s2) |
| 295 | return False; |
| 296 | s1++; |
| 297 | s2++; |
| 298 | } |
| 299 | } |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 300 | |
sewardj | c9069f2 | 2012-06-01 16:09:50 +0000 | [diff] [blame] | 301 | void vex_bzero ( void* sV, UInt n ) |
| 302 | { |
| 303 | UInt i; |
| 304 | UChar* s = (UChar*)sV; |
| 305 | /* No laughing, please. Just don't call this too often. Thank you |
| 306 | for your attention. */ |
| 307 | for (i = 0; i < n; i++) s[i] = 0; |
| 308 | } |
| 309 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 310 | |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 311 | /* Convert N0 into ascii in BUF, which is assumed to be big enough (at |
| 312 | least 67 bytes long). Observe BASE, SYNED and HEXCAPS. */ |
| 313 | static |
| 314 | void convert_int ( /*OUT*/HChar* buf, Long n0, |
| 315 | Int base, Bool syned, Bool hexcaps ) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 316 | { |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 317 | ULong u0; |
| 318 | HChar c; |
| 319 | Bool minus = False; |
| 320 | Int i, j, bufi = 0; |
| 321 | buf[bufi] = 0; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 322 | |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 323 | if (syned) { |
| 324 | if (n0 < 0) { |
| 325 | minus = True; |
| 326 | u0 = (ULong)(-n0); |
| 327 | } else { |
| 328 | u0 = (ULong)(n0); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 329 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 330 | } else { |
| 331 | u0 = (ULong)n0; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 332 | } |
| 333 | |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 334 | while (1) { |
sewardj | c7cd214 | 2005-09-09 22:31:49 +0000 | [diff] [blame] | 335 | buf[bufi++] = toHChar('0' + toUInt(u0 % base)); |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 336 | u0 /= base; |
| 337 | if (u0 == 0) break; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 338 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 339 | if (minus) |
| 340 | buf[bufi++] = '-'; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 341 | |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 342 | buf[bufi] = 0; |
| 343 | for (i = 0; i < bufi; i++) |
| 344 | if (buf[i] > '9') |
sewardj | c7cd214 | 2005-09-09 22:31:49 +0000 | [diff] [blame] | 345 | buf[i] = toHChar(buf[i] + (hexcaps ? 'A' : 'a') - '9' - 1); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 346 | |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 347 | i = 0; |
| 348 | j = bufi-1; |
| 349 | while (i <= j) { |
| 350 | c = buf[i]; |
| 351 | buf[i] = buf[j]; |
| 352 | buf[j] = c; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 353 | i++; |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 354 | j--; |
| 355 | } |
| 356 | } |
| 357 | |
| 358 | |
| 359 | /* A half-arsed and buggy, but good-enough, implementation of |
| 360 | printf. */ |
| 361 | static |
| 362 | UInt vprintf_wrk ( void(*sink)(HChar), |
florian | 76714fd | 2012-09-13 20:21:42 +0000 | [diff] [blame] | 363 | const HChar* format, |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 364 | va_list ap ) |
| 365 | { |
| 366 | # define PUT(_ch) \ |
| 367 | do { sink(_ch); nout++; } \ |
| 368 | while (0) |
| 369 | |
| 370 | # define PAD(_n) \ |
| 371 | do { Int _qq = (_n); for (; _qq > 0; _qq--) PUT(padchar); } \ |
| 372 | while (0) |
| 373 | |
| 374 | # define PUTSTR(_str) \ |
florian | 55085f8 | 2012-11-21 00:36:55 +0000 | [diff] [blame] | 375 | do { const HChar* _qq = _str; for (; *_qq; _qq++) PUT(*_qq); } \ |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 376 | while (0) |
| 377 | |
florian | 76714fd | 2012-09-13 20:21:42 +0000 | [diff] [blame] | 378 | const HChar* saved_format; |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 379 | Bool longlong, ljustify; |
| 380 | HChar padchar; |
| 381 | Int fwidth, nout, len1, len2, len3; |
| 382 | HChar intbuf[100]; /* big enough for a 64-bit # in base 2 */ |
| 383 | |
| 384 | nout = 0; |
| 385 | while (1) { |
| 386 | |
| 387 | if (!format) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 388 | break; |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 389 | if (*format == 0) |
| 390 | break; |
| 391 | |
| 392 | if (*format != '%') { |
| 393 | PUT(*format); |
| 394 | format++; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 395 | continue; |
| 396 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 397 | |
| 398 | saved_format = format; |
| 399 | longlong = False; |
| 400 | ljustify = False; |
| 401 | padchar = ' '; |
| 402 | fwidth = 0; |
| 403 | format++; |
| 404 | |
| 405 | if (*format == '-') { |
| 406 | format++; |
| 407 | ljustify = True; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 408 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 409 | if (*format == '0') { |
| 410 | format++; |
| 411 | padchar = '0'; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 412 | } |
florian | 473dc16 | 2012-12-16 22:44:32 +0000 | [diff] [blame] | 413 | if (*format == '*') { |
| 414 | fwidth = va_arg(ap, Int); |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 415 | format++; |
florian | 473dc16 | 2012-12-16 22:44:32 +0000 | [diff] [blame] | 416 | } else { |
| 417 | while (*format >= '0' && *format <= '9') { |
| 418 | fwidth = fwidth * 10 + (*format - '0'); |
| 419 | format++; |
| 420 | } |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 421 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 422 | if (*format == 'l') { |
| 423 | format++; |
| 424 | if (*format == 'l') { |
| 425 | format++; |
| 426 | longlong = True; |
| 427 | } |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 428 | } |
| 429 | |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 430 | switch (*format) { |
| 431 | case 's': { |
florian | 55085f8 | 2012-11-21 00:36:55 +0000 | [diff] [blame] | 432 | const HChar* str = va_arg(ap, HChar*); |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 433 | if (str == NULL) |
| 434 | str = "(null)"; |
| 435 | len1 = len3 = 0; |
| 436 | len2 = vex_strlen(str); |
cerion | 7d730cf | 2005-12-13 20:23:36 +0000 | [diff] [blame] | 437 | if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2; |
| 438 | len3 = ljustify ? fwidth-len2 : 0; } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 439 | PAD(len1); PUTSTR(str); PAD(len3); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 440 | break; |
cerion | b85e8bb | 2005-02-16 08:54:33 +0000 | [diff] [blame] | 441 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 442 | case 'c': { |
| 443 | HChar c = (HChar)va_arg(ap, int); |
| 444 | HChar str[2]; |
| 445 | str[0] = c; |
| 446 | str[1] = 0; |
| 447 | len1 = len3 = 0; |
| 448 | len2 = vex_strlen(str); |
cerion | 7d730cf | 2005-12-13 20:23:36 +0000 | [diff] [blame] | 449 | if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2; |
| 450 | len3 = ljustify ? fwidth-len2 : 0; } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 451 | PAD(len1); PUTSTR(str); PAD(len3); |
| 452 | break; |
| 453 | } |
| 454 | case 'd': { |
| 455 | Long l; |
| 456 | if (longlong) { |
| 457 | l = va_arg(ap, Long); |
| 458 | } else { |
| 459 | l = (Long)va_arg(ap, Int); |
| 460 | } |
| 461 | convert_int(intbuf, l, 10/*base*/, True/*signed*/, |
| 462 | False/*irrelevant*/); |
| 463 | len1 = len3 = 0; |
| 464 | len2 = vex_strlen(intbuf); |
cerion | 7d730cf | 2005-12-13 20:23:36 +0000 | [diff] [blame] | 465 | if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2; |
| 466 | len3 = ljustify ? fwidth-len2 : 0; } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 467 | PAD(len1); PUTSTR(intbuf); PAD(len3); |
| 468 | break; |
| 469 | } |
| 470 | case 'u': |
| 471 | case 'x': |
| 472 | case 'X': { |
| 473 | Int base = *format == 'u' ? 10 : 16; |
| 474 | Bool hexcaps = True; /* *format == 'X'; */ |
| 475 | ULong l; |
| 476 | if (longlong) { |
| 477 | l = va_arg(ap, ULong); |
| 478 | } else { |
| 479 | l = (ULong)va_arg(ap, UInt); |
| 480 | } |
| 481 | convert_int(intbuf, l, base, False/*unsigned*/, hexcaps); |
| 482 | len1 = len3 = 0; |
| 483 | len2 = vex_strlen(intbuf); |
cerion | 7d730cf | 2005-12-13 20:23:36 +0000 | [diff] [blame] | 484 | if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2; |
| 485 | len3 = ljustify ? fwidth-len2 : 0; } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 486 | PAD(len1); PUTSTR(intbuf); PAD(len3); |
| 487 | break; |
| 488 | } |
| 489 | case 'p': |
| 490 | case 'P': { |
sewardj | c7cd214 | 2005-09-09 22:31:49 +0000 | [diff] [blame] | 491 | Bool hexcaps = toBool(*format == 'P'); |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 492 | ULong l = Ptr_to_ULong( va_arg(ap, void*) ); |
| 493 | convert_int(intbuf, l, 16/*base*/, False/*unsigned*/, hexcaps); |
| 494 | len1 = len3 = 0; |
| 495 | len2 = vex_strlen(intbuf)+2; |
cerion | 7d730cf | 2005-12-13 20:23:36 +0000 | [diff] [blame] | 496 | if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2; |
| 497 | len3 = ljustify ? fwidth-len2 : 0; } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 498 | PAD(len1); PUT('0'); PUT('x'); PUTSTR(intbuf); PAD(len3); |
| 499 | break; |
| 500 | } |
sewardj | eb17e49 | 2007-08-25 23:07:44 +0000 | [diff] [blame] | 501 | case '%': { |
| 502 | PUT('%'); |
| 503 | break; |
| 504 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 505 | default: |
| 506 | /* no idea what it is. Print the format literally and |
| 507 | move on. */ |
| 508 | while (saved_format <= format) { |
| 509 | PUT(*saved_format); |
| 510 | saved_format++; |
cerion | b85e8bb | 2005-02-16 08:54:33 +0000 | [diff] [blame] | 511 | } |
| 512 | break; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 513 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 514 | |
| 515 | format++; |
| 516 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 517 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 518 | |
| 519 | return nout; |
| 520 | |
| 521 | # undef PUT |
| 522 | # undef PAD |
| 523 | # undef PUTSTR |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 524 | } |
| 525 | |
| 526 | |
| 527 | /* A general replacement for printf(). Note that only low-level |
| 528 | debugging info should be sent via here. The official route is to |
| 529 | to use vg_message(). This interface is deprecated. |
| 530 | */ |
sewardj | 5827784 | 2005-02-07 03:11:17 +0000 | [diff] [blame] | 531 | static HChar myprintf_buf[1000]; |
| 532 | static Int n_myprintf_buf; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 533 | |
sewardj | 5827784 | 2005-02-07 03:11:17 +0000 | [diff] [blame] | 534 | static void add_to_myprintf_buf ( HChar c ) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 535 | { |
sewardj | c7cd214 | 2005-09-09 22:31:49 +0000 | [diff] [blame] | 536 | Bool emit = toBool(c == '\n' || n_myprintf_buf >= 1000-10 /*paranoia*/); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 537 | myprintf_buf[n_myprintf_buf++] = c; |
| 538 | myprintf_buf[n_myprintf_buf] = 0; |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 539 | if (emit) { |
| 540 | (*vex_log_bytes)( myprintf_buf, vex_strlen(myprintf_buf) ); |
| 541 | n_myprintf_buf = 0; |
| 542 | myprintf_buf[n_myprintf_buf] = 0; |
| 543 | } |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 544 | } |
| 545 | |
florian | 76714fd | 2012-09-13 20:21:42 +0000 | [diff] [blame] | 546 | UInt vex_printf ( const HChar* format, ... ) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 547 | { |
| 548 | UInt ret; |
| 549 | va_list vargs; |
| 550 | va_start(vargs,format); |
| 551 | |
| 552 | n_myprintf_buf = 0; |
| 553 | myprintf_buf[n_myprintf_buf] = 0; |
| 554 | ret = vprintf_wrk ( add_to_myprintf_buf, format, vargs ); |
| 555 | |
| 556 | if (n_myprintf_buf > 0) { |
| 557 | (*vex_log_bytes)( myprintf_buf, n_myprintf_buf ); |
| 558 | } |
| 559 | |
| 560 | va_end(vargs); |
| 561 | |
| 562 | return ret; |
| 563 | } |
| 564 | |
| 565 | |
sewardj | 41f43bc | 2004-07-08 14:23:22 +0000 | [diff] [blame] | 566 | /* A general replacement for sprintf(). */ |
| 567 | |
sewardj | 5827784 | 2005-02-07 03:11:17 +0000 | [diff] [blame] | 568 | static HChar *vg_sprintf_ptr; |
sewardj | 41f43bc | 2004-07-08 14:23:22 +0000 | [diff] [blame] | 569 | |
sewardj | 5827784 | 2005-02-07 03:11:17 +0000 | [diff] [blame] | 570 | static void add_to_vg_sprintf_buf ( HChar c ) |
sewardj | 41f43bc | 2004-07-08 14:23:22 +0000 | [diff] [blame] | 571 | { |
| 572 | *vg_sprintf_ptr++ = c; |
| 573 | } |
| 574 | |
florian | 76714fd | 2012-09-13 20:21:42 +0000 | [diff] [blame] | 575 | UInt vex_sprintf ( HChar* buf, const HChar *format, ... ) |
sewardj | 41f43bc | 2004-07-08 14:23:22 +0000 | [diff] [blame] | 576 | { |
| 577 | Int ret; |
| 578 | va_list vargs; |
| 579 | |
| 580 | vg_sprintf_ptr = buf; |
| 581 | |
| 582 | va_start(vargs,format); |
| 583 | |
| 584 | ret = vprintf_wrk ( add_to_vg_sprintf_buf, format, vargs ); |
| 585 | add_to_vg_sprintf_buf(0); |
| 586 | |
| 587 | va_end(vargs); |
| 588 | |
| 589 | vassert(vex_strlen(buf) == ret); |
| 590 | return ret; |
| 591 | } |
| 592 | |
| 593 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 594 | /*---------------------------------------------------------------*/ |
sewardj | cef7d3e | 2009-07-02 12:21:59 +0000 | [diff] [blame] | 595 | /*--- end main_util.c ---*/ |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 596 | /*---------------------------------------------------------------*/ |