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 | |
florian | 04fc6b1 | 2014-12-29 20:22:26 +0000 | [diff] [blame] | 206 | void* LibVEX_Alloc ( SizeT nbytes ) |
florian | bde3406 | 2014-10-11 14:48:38 +0000 | [diff] [blame] | 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; |
florian | 04fc6b1 | 2014-12-29 20:22:26 +0000 | [diff] [blame] | 232 | SizeT ALIGN; |
florian | bde3406 | 2014-10-11 14:48:38 +0000 | [diff] [blame] | 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 | |
florian | eebdb2b | 2014-12-10 16:08:09 +0000 | [diff] [blame] | 266 | /* To be used in assert-like (i.e. should never ever happen) situations */ |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 267 | __attribute__ ((noreturn)) |
florian | 76714fd | 2012-09-13 20:21:42 +0000 | [diff] [blame] | 268 | void vpanic ( const HChar* str ) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 269 | { |
| 270 | vex_printf("\nvex: the `impossible' happened:\n %s\n", str); |
| 271 | (*vex_failure_exit)(); |
| 272 | } |
| 273 | |
| 274 | |
| 275 | /*---------------------------------------------------------*/ |
| 276 | /*--- vex_printf ---*/ |
| 277 | /*---------------------------------------------------------*/ |
| 278 | |
| 279 | /* This should be the only <...> include in the entire VEX library. |
| 280 | New code for vex_util.c should go above this point. */ |
| 281 | #include <stdarg.h> |
| 282 | |
florian | 04fc6b1 | 2014-12-29 20:22:26 +0000 | [diff] [blame] | 283 | SizeT vex_strlen ( const HChar* str ) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 284 | { |
florian | 04fc6b1 | 2014-12-29 20:22:26 +0000 | [diff] [blame] | 285 | SizeT i = 0; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 286 | while (str[i] != 0) i++; |
| 287 | return i; |
| 288 | } |
| 289 | |
sewardj | 5827784 | 2005-02-07 03:11:17 +0000 | [diff] [blame] | 290 | Bool vex_streq ( const HChar* s1, const HChar* s2 ) |
sewardj | 36ca513 | 2004-07-24 13:12:23 +0000 | [diff] [blame] | 291 | { |
| 292 | while (True) { |
| 293 | if (*s1 == 0 && *s2 == 0) |
| 294 | return True; |
| 295 | if (*s1 != *s2) |
| 296 | return False; |
| 297 | s1++; |
| 298 | s2++; |
| 299 | } |
| 300 | } |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 301 | |
florian | 04fc6b1 | 2014-12-29 20:22:26 +0000 | [diff] [blame] | 302 | void vex_bzero ( void* sV, SizeT n ) |
sewardj | c9069f2 | 2012-06-01 16:09:50 +0000 | [diff] [blame] | 303 | { |
florian | 04fc6b1 | 2014-12-29 20:22:26 +0000 | [diff] [blame] | 304 | SizeT i; |
sewardj | c9069f2 | 2012-06-01 16:09:50 +0000 | [diff] [blame] | 305 | UChar* s = (UChar*)sV; |
| 306 | /* No laughing, please. Just don't call this too often. Thank you |
| 307 | for your attention. */ |
| 308 | for (i = 0; i < n; i++) s[i] = 0; |
| 309 | } |
| 310 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 311 | |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 312 | /* Convert N0 into ascii in BUF, which is assumed to be big enough (at |
| 313 | least 67 bytes long). Observe BASE, SYNED and HEXCAPS. */ |
| 314 | static |
| 315 | void convert_int ( /*OUT*/HChar* buf, Long n0, |
| 316 | Int base, Bool syned, Bool hexcaps ) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 317 | { |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 318 | ULong u0; |
| 319 | HChar c; |
| 320 | Bool minus = False; |
| 321 | Int i, j, bufi = 0; |
| 322 | buf[bufi] = 0; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 323 | |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 324 | if (syned) { |
| 325 | if (n0 < 0) { |
| 326 | minus = True; |
| 327 | u0 = (ULong)(-n0); |
| 328 | } else { |
| 329 | u0 = (ULong)(n0); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 330 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 331 | } else { |
| 332 | u0 = (ULong)n0; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 333 | } |
| 334 | |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 335 | while (1) { |
sewardj | c7cd214 | 2005-09-09 22:31:49 +0000 | [diff] [blame] | 336 | buf[bufi++] = toHChar('0' + toUInt(u0 % base)); |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 337 | u0 /= base; |
| 338 | if (u0 == 0) break; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 339 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 340 | if (minus) |
| 341 | buf[bufi++] = '-'; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 342 | |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 343 | buf[bufi] = 0; |
| 344 | for (i = 0; i < bufi; i++) |
| 345 | if (buf[i] > '9') |
sewardj | c7cd214 | 2005-09-09 22:31:49 +0000 | [diff] [blame] | 346 | buf[i] = toHChar(buf[i] + (hexcaps ? 'A' : 'a') - '9' - 1); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 347 | |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 348 | i = 0; |
| 349 | j = bufi-1; |
| 350 | while (i <= j) { |
| 351 | c = buf[i]; |
| 352 | buf[i] = buf[j]; |
| 353 | buf[j] = c; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 354 | i++; |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 355 | j--; |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | |
| 360 | /* A half-arsed and buggy, but good-enough, implementation of |
| 361 | printf. */ |
| 362 | static |
| 363 | UInt vprintf_wrk ( void(*sink)(HChar), |
florian | 76714fd | 2012-09-13 20:21:42 +0000 | [diff] [blame] | 364 | const HChar* format, |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 365 | va_list ap ) |
| 366 | { |
| 367 | # define PUT(_ch) \ |
| 368 | do { sink(_ch); nout++; } \ |
| 369 | while (0) |
| 370 | |
| 371 | # define PAD(_n) \ |
| 372 | do { Int _qq = (_n); for (; _qq > 0; _qq--) PUT(padchar); } \ |
| 373 | while (0) |
| 374 | |
| 375 | # define PUTSTR(_str) \ |
florian | 55085f8 | 2012-11-21 00:36:55 +0000 | [diff] [blame] | 376 | do { const HChar* _qq = _str; for (; *_qq; _qq++) PUT(*_qq); } \ |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 377 | while (0) |
| 378 | |
florian | 76714fd | 2012-09-13 20:21:42 +0000 | [diff] [blame] | 379 | const HChar* saved_format; |
florian | c66ba65 | 2014-12-29 19:05:37 +0000 | [diff] [blame] | 380 | Bool longlong, ljustify, is_sizet; |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 381 | HChar padchar; |
florian | 04fc6b1 | 2014-12-29 20:22:26 +0000 | [diff] [blame] | 382 | Int fwidth, nout, len1, len3; |
| 383 | SizeT len2; |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 384 | HChar intbuf[100]; /* big enough for a 64-bit # in base 2 */ |
| 385 | |
| 386 | nout = 0; |
| 387 | while (1) { |
| 388 | |
| 389 | if (!format) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 390 | break; |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 391 | if (*format == 0) |
| 392 | break; |
| 393 | |
| 394 | if (*format != '%') { |
| 395 | PUT(*format); |
| 396 | format++; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 397 | continue; |
| 398 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 399 | |
| 400 | saved_format = format; |
florian | c66ba65 | 2014-12-29 19:05:37 +0000 | [diff] [blame] | 401 | longlong = is_sizet = False; |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 402 | ljustify = False; |
| 403 | padchar = ' '; |
| 404 | fwidth = 0; |
| 405 | format++; |
| 406 | |
| 407 | if (*format == '-') { |
| 408 | format++; |
| 409 | ljustify = True; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 410 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 411 | if (*format == '0') { |
| 412 | format++; |
| 413 | padchar = '0'; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 414 | } |
florian | 473dc16 | 2012-12-16 22:44:32 +0000 | [diff] [blame] | 415 | if (*format == '*') { |
| 416 | fwidth = va_arg(ap, Int); |
florian | 04fc6b1 | 2014-12-29 20:22:26 +0000 | [diff] [blame] | 417 | vassert(fwidth >= 0); |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 418 | format++; |
florian | 473dc16 | 2012-12-16 22:44:32 +0000 | [diff] [blame] | 419 | } else { |
| 420 | while (*format >= '0' && *format <= '9') { |
| 421 | fwidth = fwidth * 10 + (*format - '0'); |
| 422 | format++; |
| 423 | } |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 424 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 425 | if (*format == 'l') { |
| 426 | format++; |
| 427 | if (*format == 'l') { |
| 428 | format++; |
florian | c66ba65 | 2014-12-29 19:05:37 +0000 | [diff] [blame] | 429 | longlong = True; |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 430 | } |
florian | c66ba65 | 2014-12-29 19:05:37 +0000 | [diff] [blame] | 431 | } else if (*format == 'z') { |
| 432 | format++; |
| 433 | is_sizet = True; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 434 | } |
| 435 | |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 436 | switch (*format) { |
| 437 | case 's': { |
florian | 55085f8 | 2012-11-21 00:36:55 +0000 | [diff] [blame] | 438 | const HChar* str = va_arg(ap, HChar*); |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 439 | if (str == NULL) |
| 440 | str = "(null)"; |
| 441 | len1 = len3 = 0; |
| 442 | len2 = vex_strlen(str); |
cerion | 7d730cf | 2005-12-13 20:23:36 +0000 | [diff] [blame] | 443 | if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2; |
| 444 | len3 = ljustify ? fwidth-len2 : 0; } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 445 | PAD(len1); PUTSTR(str); PAD(len3); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 446 | break; |
cerion | b85e8bb | 2005-02-16 08:54:33 +0000 | [diff] [blame] | 447 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 448 | case 'c': { |
| 449 | HChar c = (HChar)va_arg(ap, int); |
| 450 | HChar str[2]; |
| 451 | str[0] = c; |
| 452 | str[1] = 0; |
| 453 | len1 = len3 = 0; |
| 454 | len2 = vex_strlen(str); |
cerion | 7d730cf | 2005-12-13 20:23:36 +0000 | [diff] [blame] | 455 | if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2; |
| 456 | len3 = ljustify ? fwidth-len2 : 0; } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 457 | PAD(len1); PUTSTR(str); PAD(len3); |
| 458 | break; |
| 459 | } |
| 460 | case 'd': { |
| 461 | Long l; |
florian | c66ba65 | 2014-12-29 19:05:37 +0000 | [diff] [blame] | 462 | vassert(is_sizet == False); // %zd is obscure; we don't allow it |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 463 | if (longlong) { |
| 464 | l = va_arg(ap, Long); |
| 465 | } else { |
| 466 | l = (Long)va_arg(ap, Int); |
| 467 | } |
| 468 | convert_int(intbuf, l, 10/*base*/, True/*signed*/, |
| 469 | False/*irrelevant*/); |
| 470 | len1 = len3 = 0; |
| 471 | len2 = vex_strlen(intbuf); |
cerion | 7d730cf | 2005-12-13 20:23:36 +0000 | [diff] [blame] | 472 | if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2; |
| 473 | len3 = ljustify ? fwidth-len2 : 0; } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 474 | PAD(len1); PUTSTR(intbuf); PAD(len3); |
| 475 | break; |
| 476 | } |
| 477 | case 'u': |
| 478 | case 'x': |
| 479 | case 'X': { |
| 480 | Int base = *format == 'u' ? 10 : 16; |
| 481 | Bool hexcaps = True; /* *format == 'X'; */ |
| 482 | ULong l; |
florian | c66ba65 | 2014-12-29 19:05:37 +0000 | [diff] [blame] | 483 | if (is_sizet) { |
| 484 | l = (ULong)va_arg(ap, SizeT); |
| 485 | } else if (longlong) { |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 486 | l = va_arg(ap, ULong); |
| 487 | } else { |
| 488 | l = (ULong)va_arg(ap, UInt); |
| 489 | } |
| 490 | convert_int(intbuf, l, base, False/*unsigned*/, hexcaps); |
| 491 | len1 = len3 = 0; |
| 492 | len2 = vex_strlen(intbuf); |
cerion | 7d730cf | 2005-12-13 20:23:36 +0000 | [diff] [blame] | 493 | if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2; |
| 494 | len3 = ljustify ? fwidth-len2 : 0; } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 495 | PAD(len1); PUTSTR(intbuf); PAD(len3); |
| 496 | break; |
| 497 | } |
| 498 | case 'p': |
| 499 | case 'P': { |
sewardj | c7cd214 | 2005-09-09 22:31:49 +0000 | [diff] [blame] | 500 | Bool hexcaps = toBool(*format == 'P'); |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 501 | ULong l = Ptr_to_ULong( va_arg(ap, void*) ); |
| 502 | convert_int(intbuf, l, 16/*base*/, False/*unsigned*/, hexcaps); |
| 503 | len1 = len3 = 0; |
| 504 | len2 = vex_strlen(intbuf)+2; |
cerion | 7d730cf | 2005-12-13 20:23:36 +0000 | [diff] [blame] | 505 | if (fwidth > len2) { len1 = ljustify ? 0 : fwidth-len2; |
| 506 | len3 = ljustify ? fwidth-len2 : 0; } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 507 | PAD(len1); PUT('0'); PUT('x'); PUTSTR(intbuf); PAD(len3); |
| 508 | break; |
| 509 | } |
sewardj | eb17e49 | 2007-08-25 23:07:44 +0000 | [diff] [blame] | 510 | case '%': { |
| 511 | PUT('%'); |
| 512 | break; |
| 513 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 514 | default: |
| 515 | /* no idea what it is. Print the format literally and |
| 516 | move on. */ |
| 517 | while (saved_format <= format) { |
| 518 | PUT(*saved_format); |
| 519 | saved_format++; |
cerion | b85e8bb | 2005-02-16 08:54:33 +0000 | [diff] [blame] | 520 | } |
| 521 | break; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 522 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 523 | |
| 524 | format++; |
| 525 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 526 | } |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 527 | |
| 528 | return nout; |
| 529 | |
| 530 | # undef PUT |
| 531 | # undef PAD |
| 532 | # undef PUTSTR |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 533 | } |
| 534 | |
| 535 | |
| 536 | /* A general replacement for printf(). Note that only low-level |
| 537 | debugging info should be sent via here. The official route is to |
| 538 | to use vg_message(). This interface is deprecated. |
| 539 | */ |
sewardj | 5827784 | 2005-02-07 03:11:17 +0000 | [diff] [blame] | 540 | static HChar myprintf_buf[1000]; |
| 541 | static Int n_myprintf_buf; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 542 | |
sewardj | 5827784 | 2005-02-07 03:11:17 +0000 | [diff] [blame] | 543 | static void add_to_myprintf_buf ( HChar c ) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 544 | { |
sewardj | c7cd214 | 2005-09-09 22:31:49 +0000 | [diff] [blame] | 545 | Bool emit = toBool(c == '\n' || n_myprintf_buf >= 1000-10 /*paranoia*/); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 546 | myprintf_buf[n_myprintf_buf++] = c; |
| 547 | myprintf_buf[n_myprintf_buf] = 0; |
sewardj | da46fdd | 2005-08-25 21:20:18 +0000 | [diff] [blame] | 548 | if (emit) { |
| 549 | (*vex_log_bytes)( myprintf_buf, vex_strlen(myprintf_buf) ); |
| 550 | n_myprintf_buf = 0; |
| 551 | myprintf_buf[n_myprintf_buf] = 0; |
| 552 | } |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 553 | } |
| 554 | |
florian | eebdb2b | 2014-12-10 16:08:09 +0000 | [diff] [blame] | 555 | static UInt vex_vprintf ( const HChar* format, va_list vargs ) |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 556 | { |
| 557 | UInt ret; |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 558 | |
| 559 | n_myprintf_buf = 0; |
| 560 | myprintf_buf[n_myprintf_buf] = 0; |
| 561 | ret = vprintf_wrk ( add_to_myprintf_buf, format, vargs ); |
| 562 | |
| 563 | if (n_myprintf_buf > 0) { |
| 564 | (*vex_log_bytes)( myprintf_buf, n_myprintf_buf ); |
| 565 | } |
| 566 | |
florian | eebdb2b | 2014-12-10 16:08:09 +0000 | [diff] [blame] | 567 | return ret; |
| 568 | } |
| 569 | |
| 570 | UInt vex_printf ( const HChar* format, ... ) |
| 571 | { |
| 572 | UInt ret; |
| 573 | va_list vargs; |
| 574 | va_start(vargs, format); |
| 575 | ret = vex_vprintf(format, vargs); |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 576 | va_end(vargs); |
| 577 | |
| 578 | return ret; |
| 579 | } |
| 580 | |
florian | eebdb2b | 2014-12-10 16:08:09 +0000 | [diff] [blame] | 581 | /* Use this function to communicate to users that a (legitimate) situation |
| 582 | occured that we cannot handle (yet). */ |
| 583 | __attribute__ ((noreturn)) |
| 584 | void vfatal ( const HChar* format, ... ) |
| 585 | { |
| 586 | va_list vargs; |
| 587 | va_start(vargs, format); |
| 588 | vex_vprintf( format, vargs ); |
| 589 | va_end(vargs); |
| 590 | vex_printf("Cannot continue. Good-bye\n\n"); |
| 591 | |
| 592 | (*vex_failure_exit)(); |
| 593 | } |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 594 | |
sewardj | 41f43bc | 2004-07-08 14:23:22 +0000 | [diff] [blame] | 595 | /* A general replacement for sprintf(). */ |
| 596 | |
sewardj | 5827784 | 2005-02-07 03:11:17 +0000 | [diff] [blame] | 597 | static HChar *vg_sprintf_ptr; |
sewardj | 41f43bc | 2004-07-08 14:23:22 +0000 | [diff] [blame] | 598 | |
sewardj | 5827784 | 2005-02-07 03:11:17 +0000 | [diff] [blame] | 599 | static void add_to_vg_sprintf_buf ( HChar c ) |
sewardj | 41f43bc | 2004-07-08 14:23:22 +0000 | [diff] [blame] | 600 | { |
| 601 | *vg_sprintf_ptr++ = c; |
| 602 | } |
| 603 | |
florian | 76714fd | 2012-09-13 20:21:42 +0000 | [diff] [blame] | 604 | UInt vex_sprintf ( HChar* buf, const HChar *format, ... ) |
sewardj | 41f43bc | 2004-07-08 14:23:22 +0000 | [diff] [blame] | 605 | { |
| 606 | Int ret; |
| 607 | va_list vargs; |
| 608 | |
| 609 | vg_sprintf_ptr = buf; |
| 610 | |
| 611 | va_start(vargs,format); |
| 612 | |
| 613 | ret = vprintf_wrk ( add_to_vg_sprintf_buf, format, vargs ); |
| 614 | add_to_vg_sprintf_buf(0); |
| 615 | |
| 616 | va_end(vargs); |
| 617 | |
| 618 | vassert(vex_strlen(buf) == ret); |
| 619 | return ret; |
| 620 | } |
| 621 | |
| 622 | |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 623 | /*---------------------------------------------------------------*/ |
sewardj | cef7d3e | 2009-07-02 12:21:59 +0000 | [diff] [blame] | 624 | /*--- end main_util.c ---*/ |
sewardj | 35421a3 | 2004-07-05 13:12:34 +0000 | [diff] [blame] | 625 | /*---------------------------------------------------------------*/ |