sewardj | 2da4784 | 2006-10-17 01:23:07 +0000 | [diff] [blame^] | 1 | |
| 2 | /*--------------------------------------------------------------------*/ |
| 3 | /*--- Startup: create initial process image on AIX5 ---*/ |
| 4 | /*--- initimg-aix5.c ---*/ |
| 5 | /*--------------------------------------------------------------------*/ |
| 6 | |
| 7 | /* |
| 8 | This file is part of Valgrind, a dynamic binary instrumentation |
| 9 | framework. |
| 10 | |
| 11 | Copyright (C) 2006-2006 OpenWorks LLP |
| 12 | info@open-works.co.uk |
| 13 | |
| 14 | This program is free software; you can redistribute it and/or |
| 15 | modify it under the terms of the GNU General Public License as |
| 16 | published by the Free Software Foundation; either version 2 of the |
| 17 | License, or (at your option) any later version. |
| 18 | |
| 19 | This program is distributed in the hope that it will be useful, but |
| 20 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 22 | General Public License for more details. |
| 23 | |
| 24 | You should have received a copy of the GNU General Public License |
| 25 | along with this program; if not, write to the Free Software |
| 26 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 27 | 02111-1307, USA. |
| 28 | |
| 29 | The GNU General Public License is contained in the file COPYING. |
| 30 | */ |
| 31 | |
| 32 | #include "pub_core_basics.h" |
| 33 | #include "pub_core_vki.h" |
| 34 | #include "pub_core_vkiscnums.h" |
| 35 | #include "pub_core_debuglog.h" |
| 36 | #include "pub_core_libcbase.h" |
| 37 | #include "pub_core_libcassert.h" |
| 38 | #include "pub_core_libcfile.h" |
| 39 | #include "pub_core_libcproc.h" |
| 40 | #include "pub_core_libcprint.h" |
| 41 | #include "pub_core_clientstate.h" |
| 42 | #include "pub_core_aspacemgr.h" |
| 43 | #include "pub_core_mallocfree.h" |
| 44 | #include "pub_core_machine.h" |
| 45 | #include "pub_core_ume.h" |
| 46 | #include "pub_core_options.h" |
| 47 | #include "pub_core_threadstate.h" /* ThreadArchState */ |
| 48 | #include "pub_core_tooliface.h" /* VG_TRACK */ |
| 49 | #include "pub_core_trampoline.h" /* VG_(ppc32_aix5_do_preloads_then_start_client) */ |
| 50 | #include "pub_core_syscall.h" // VG_(do_syscall1) |
| 51 | #include "pub_core_initimg.h" /* self */ |
| 52 | |
| 53 | #include "simple_huffman.c" |
| 54 | |
| 55 | #if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) |
| 56 | #error "This should only be compiled on AIX" |
| 57 | #endif |
| 58 | |
| 59 | |
| 60 | static void diagnose_load_failure ( void ); |
| 61 | |
| 62 | /* --- Create the client's initial memory image. --- */ |
| 63 | |
| 64 | ClientInitImgInfo |
| 65 | VG_(setup_client_initial_image)( |
| 66 | /*IN*/ HChar** argv, |
| 67 | /*IN*/ HChar** envp, |
| 68 | /*IN*/ HChar* toolname, |
| 69 | /*IN*/ Addr clstack_top, |
| 70 | /*IN*/ SizeT clstack_max_size |
| 71 | ) |
| 72 | { |
| 73 | ClientInitImgInfo ciii; |
| 74 | |
| 75 | /* Set up an AIX5PreloadPage structure with the names of |
| 76 | |
| 77 | $VALGRIND_LIB/PLATFORM/vgpreload_core.so |
| 78 | $VALGRIND_LIB/PLATFORM/vgpreload_TOOL.so, if it exists |
| 79 | xxx in "LD_PRELOAD=xxx", if it exists |
| 80 | |
| 81 | The client is started by running (on the simulator, of course) |
| 82 | VG_(ppc{32,64}_aix5_do_preloads_then_start_client), which uses |
| 83 | __loadx/_kload to load these .so's. When the preloading is |
| 84 | done, various guest registers are restored to what they are |
| 85 | really supposed to be at client startup, so these values too are |
| 86 | stored in the AIX5PreloadPage. Finally, we jump to the client's |
| 87 | entry point address. |
| 88 | */ |
| 89 | const HChar* _so = ".so"; |
| 90 | const HChar* vgpreload_ = "vgpreload_"; |
| 91 | const HChar* vgpreload_core_so = "vgpreload_core.so"; |
| 92 | const HChar* errmsg_str |
| 93 | = "valgrind: FATAL: core/tool/LD_PRELOAD= " |
| 94 | "preload failed.\n"; |
| 95 | Int plcore_len, pltool_len, ld_pre_len, errmsg_len; |
| 96 | HChar *plcore_str, *pltool_str, *ld_pre_str; |
| 97 | Bool have_tool_so, have_ld_pre; |
| 98 | |
| 99 | AIX5PreloadPage* pp; |
| 100 | UChar* pc; |
| 101 | Int szB, szPG; |
| 102 | SysRes sres; |
| 103 | |
| 104 | vg_assert( toolname ); |
| 105 | pltool_len = VG_(strlen)( VG_(libdir) ) |
| 106 | + 1 /*slash*/ |
| 107 | + VG_(strlen)(VG_PLATFORM) |
| 108 | + 1 /*slash*/ |
| 109 | + VG_(strlen)( vgpreload_ ) |
| 110 | + VG_(strlen)( toolname ) |
| 111 | + VG_(strlen)( _so ) |
| 112 | + 1 /*NUL*/; |
| 113 | vg_assert(pltool_len > 0); |
| 114 | pltool_str = VG_(malloc)( pltool_len ); |
| 115 | pltool_str[0] = 0; |
| 116 | VG_(strcat)( pltool_str, VG_(libdir) ); |
| 117 | VG_(strcat)( pltool_str, "/" ); |
| 118 | VG_(strcat)( pltool_str, VG_PLATFORM ); |
| 119 | VG_(strcat)( pltool_str, "/" ); |
| 120 | VG_(strcat)( pltool_str, vgpreload_ ); |
| 121 | VG_(strcat)( pltool_str, toolname ); |
| 122 | VG_(strcat)( pltool_str, _so ); |
| 123 | vg_assert( pltool_str[pltool_len-1] == 0); |
| 124 | vg_assert( VG_(strlen)(pltool_str) == pltool_len-1 ); |
| 125 | |
| 126 | plcore_len = VG_(strlen)( VG_(libdir) ) |
| 127 | + 1 /*slash*/ |
| 128 | + VG_(strlen)(VG_PLATFORM) |
| 129 | + 1 /*slash*/ |
| 130 | + VG_(strlen)( vgpreload_core_so ) |
| 131 | + 1 /*NUL*/; |
| 132 | vg_assert(plcore_len > 0); |
| 133 | plcore_str = VG_(malloc)( plcore_len ); |
| 134 | plcore_str[0] = 0; |
| 135 | VG_(strcat)( plcore_str, VG_(libdir) ); |
| 136 | VG_(strcat)( plcore_str, "/" ); |
| 137 | VG_(strcat)( plcore_str, VG_PLATFORM ); |
| 138 | VG_(strcat)( plcore_str, "/" ); |
| 139 | VG_(strcat)( plcore_str, vgpreload_core_so ); |
| 140 | vg_assert( plcore_str[plcore_len-1] == 0 ); |
| 141 | vg_assert( VG_(strlen)(plcore_str) == plcore_len-1 ); |
| 142 | |
| 143 | errmsg_len = VG_(strlen)( errmsg_str ) |
| 144 | + 1 /*NUL*/; |
| 145 | |
| 146 | ld_pre_str = VG_(getenv)("LD_PRELOAD"); |
| 147 | if (ld_pre_str && VG_(strlen)(ld_pre_str) > 0) { |
| 148 | have_ld_pre = True; |
| 149 | ld_pre_len = VG_(strlen)(ld_pre_str) + 1/*NUL*/; |
| 150 | ld_pre_str = VG_(malloc)( ld_pre_len ); |
| 151 | ld_pre_str[0] = 0; |
| 152 | VG_(strcat)( ld_pre_str, VG_(getenv)("LD_PRELOAD") ); |
| 153 | vg_assert( ld_pre_str[ld_pre_len-1] == 0); |
| 154 | vg_assert( VG_(strlen)( ld_pre_str ) == ld_pre_len - 1 ); |
| 155 | } else { |
| 156 | have_ld_pre = False; |
| 157 | ld_pre_len = 0; |
| 158 | ld_pre_str = NULL; |
| 159 | } |
| 160 | |
| 161 | VG_(debugLog)(1, "initimg", "plcore_str = '%s'\n", plcore_str ); |
| 162 | VG_(debugLog)(1, "initimg", "pltool_str = '%s'\n", pltool_str ); |
| 163 | VG_(debugLog)(1, "initimg", "ld_pre_str = '%s'\n", ld_pre_str ); |
| 164 | |
| 165 | if (0 != VG_(access)(plcore_str, True,False,True)) |
| 166 | VG_(err_config_error)("Can't find core preload " |
| 167 | "(vgpreload_core.so)"); |
| 168 | |
| 169 | have_tool_so = 0 == VG_(access)(pltool_str, True,False,True); |
| 170 | |
| 171 | /* Figure out how much space is needed for an AIX5PreloadInfo |
| 172 | followed by the three preload strings. */ |
| 173 | |
| 174 | vg_assert((sizeof(AIX5PreloadPage) % 4) == 0); /* paranoia */ |
| 175 | |
| 176 | szB = sizeof(AIX5PreloadPage) + plcore_len |
| 177 | + (have_tool_so ? pltool_len : 0) |
| 178 | + (have_ld_pre ? ld_pre_len : 0) |
| 179 | + errmsg_len; |
| 180 | szPG = VG_PGROUNDUP(szB+1) / VKI_PAGE_SIZE; |
| 181 | VG_(debugLog)(2, "initimg", "preload page size: %d bytes, %d pages\n", szB, szPG); |
| 182 | |
| 183 | vg_assert(szB > 0); |
| 184 | vg_assert(szB < szPG * VKI_PAGE_SIZE); |
| 185 | |
| 186 | /* We'll need szPG pages of anonymous, rw-, client space (needs w |
| 187 | so we can write it here) */ |
| 188 | sres = VG_(am_mmap_anon_float_client) |
| 189 | ( szPG * VKI_PAGE_SIZE, VKI_PROT_READ|VKI_PROT_WRITE); |
| 190 | if (sres.isError) |
| 191 | VG_(err_config_error)("Can't allocate client page(s) " |
| 192 | "for preload info"); |
| 193 | pp = (AIX5PreloadPage*)sres.res; |
| 194 | |
| 195 | VG_(debugLog)(2, "initimg", "preload page allocation succeeded at %p\n", pp); |
| 196 | |
| 197 | /* Zero out the initial structure. */ |
| 198 | VG_(memset)(pp, 0, sizeof(AIX5PreloadPage)); |
| 199 | |
| 200 | pc = (UChar*)pp; |
| 201 | pc += sizeof(AIX5PreloadPage); |
| 202 | VG_(memcpy)(pc, plcore_str, plcore_len); |
| 203 | pp->off_preloadcorename = pc - (UChar*)pp; |
| 204 | pc += plcore_len; |
| 205 | if (have_tool_so) { |
| 206 | VG_(memcpy)(pc, pltool_str, pltool_len); |
| 207 | pp->off_preloadtoolname = pc - (UChar*)pp; |
| 208 | pc += pltool_len; |
| 209 | } |
| 210 | if (have_ld_pre) { |
| 211 | VG_(memcpy)(pc, ld_pre_str, ld_pre_len); |
| 212 | pp->off_ld_preloadname = pc - (UChar*)pp; |
| 213 | pc += ld_pre_len; |
| 214 | } |
| 215 | VG_(memcpy)(pc, errmsg_str, errmsg_len); |
| 216 | pp->off_errmsg = pc - (UChar*)pp; |
| 217 | pp->len_errmsg = errmsg_len - 1; /* -1: skip terminating NUL */ |
| 218 | |
| 219 | vg_assert(pc <= ((UChar*)pp) - 1 + szPG * VKI_PAGE_SIZE); |
| 220 | |
| 221 | VG_(free)(plcore_str); |
| 222 | VG_(free)(pltool_str); |
| 223 | |
| 224 | /* Fill in all the other preload page fields that we can right |
| 225 | now. */ |
| 226 | # if defined(VGP_ppc32_aix5) |
| 227 | vg_assert(__NR_AIX5___loadx != __NR_AIX5_UNKNOWN); |
| 228 | pp->nr_load = __NR_AIX5___loadx; |
| 229 | # else /* defined(VGP_ppc64_aix5) */ |
| 230 | vg_assert(__NR_AIX5_kload != __NR_AIX5_UNKNOWN); |
| 231 | pp->nr_load = __NR_AIX5_kload; |
| 232 | # endif |
| 233 | |
| 234 | vg_assert(__NR_AIX5_kwrite != __NR_AIX5_UNKNOWN); |
| 235 | pp->nr_kwrite = __NR_AIX5_kwrite; /* kwrite */ |
| 236 | |
| 237 | vg_assert(__NR_AIX5__exit != __NR_AIX5_UNKNOWN); |
| 238 | pp->nr__exit = __NR_AIX5__exit; /* _exit */ |
| 239 | |
| 240 | pp->p_diagnose_load_failure = &diagnose_load_failure; |
| 241 | |
| 242 | ciii.preloadpage = pp; |
| 243 | ciii.intregs37 = 0; /* filled in in m_main.c */ |
| 244 | return ciii; |
| 245 | } |
| 246 | |
| 247 | |
| 248 | /* --- Finalise the initial image and register state. --- */ |
| 249 | |
| 250 | static UChar unz_page[VKI_PAGE_SIZE]; |
| 251 | |
| 252 | static UInt compute_adler32 ( void* addr, UWord len ) |
| 253 | { |
| 254 | UInt s1 = 1; |
| 255 | UInt s2 = 0; |
| 256 | UChar* buf = (UChar*)addr; |
| 257 | while (len > 0) { |
| 258 | s1 += buf[0]; |
| 259 | s2 += s1; |
| 260 | s1 %= 65521; |
| 261 | s2 %= 65521; |
| 262 | len--; |
| 263 | buf++; |
| 264 | } |
| 265 | return (s2 << 16) + s1; |
| 266 | } |
| 267 | |
| 268 | void VG_(finalise_thread1state)( /*MOD*/ThreadArchState* arch, |
| 269 | ClientInitImgInfo ciii ) |
| 270 | { |
| 271 | UInt adler32_act; |
| 272 | SysRes sres; |
| 273 | /* On AIX we get a block of 37 words telling us the initial state |
| 274 | for (GPR0 .. GPR31, PC, CR, LR, CTR, XER), and we start with all |
| 275 | the other registers zeroed. */ |
| 276 | |
| 277 | # if defined(VGP_ppc32_aix5) |
| 278 | |
| 279 | vg_assert(0 == sizeof(VexGuestPPC32State) % 8); |
| 280 | |
| 281 | /* Zero out the initial state, and set up the simulated FPU in a |
| 282 | sane way. */ |
| 283 | LibVEX_GuestPPC32_initialise(&arch->vex); |
| 284 | |
| 285 | /* Zero out the shadow area. */ |
| 286 | VG_(memset)(&arch->vex_shadow, 0, sizeof(VexGuestPPC32State)); |
| 287 | |
| 288 | # else /* defined(VGP_ppc64_aix5) */ |
| 289 | |
| 290 | vg_assert(0 == sizeof(VexGuestPPC64State) % 8); |
| 291 | |
| 292 | /* Zero out the initial state, and set up the simulated FPU in a |
| 293 | sane way. */ |
| 294 | LibVEX_GuestPPC64_initialise(&arch->vex); |
| 295 | |
| 296 | /* Zero out the shadow area. */ |
| 297 | VG_(memset)(&arch->vex_shadow, 0, sizeof(VexGuestPPC64State)); |
| 298 | |
| 299 | # endif |
| 300 | |
| 301 | /* ciii.intregs37 contains the integer register state as it needs |
| 302 | to be at client startup. These values are supplied by the |
| 303 | launcher. The 37 regs are:initial values from launcher for: |
| 304 | GPR0 .. GPR31, PC, CR, LR, CTR, XER. */ |
| 305 | |
| 306 | /* Put essential stuff into the new state. */ |
| 307 | arch->vex.guest_GPR0 = (UWord)ciii.intregs37[0]; |
| 308 | arch->vex.guest_GPR1 = (UWord)ciii.intregs37[1]; |
| 309 | arch->vex.guest_GPR2 = (UWord)ciii.intregs37[2]; |
| 310 | arch->vex.guest_GPR3 = (UWord)ciii.intregs37[3]; |
| 311 | arch->vex.guest_GPR4 = (UWord)ciii.intregs37[4]; |
| 312 | arch->vex.guest_GPR5 = (UWord)ciii.intregs37[5]; |
| 313 | arch->vex.guest_GPR6 = (UWord)ciii.intregs37[6]; |
| 314 | arch->vex.guest_GPR7 = (UWord)ciii.intregs37[7]; |
| 315 | arch->vex.guest_GPR8 = (UWord)ciii.intregs37[8]; |
| 316 | arch->vex.guest_GPR9 = (UWord)ciii.intregs37[9]; |
| 317 | arch->vex.guest_GPR10 = (UWord)ciii.intregs37[10]; |
| 318 | arch->vex.guest_GPR11 = (UWord)ciii.intregs37[11]; |
| 319 | arch->vex.guest_GPR12 = (UWord)ciii.intregs37[12]; |
| 320 | arch->vex.guest_GPR13 = (UWord)ciii.intregs37[13]; |
| 321 | arch->vex.guest_GPR14 = (UWord)ciii.intregs37[14]; |
| 322 | arch->vex.guest_GPR15 = (UWord)ciii.intregs37[15]; |
| 323 | arch->vex.guest_GPR16 = (UWord)ciii.intregs37[16]; |
| 324 | arch->vex.guest_GPR17 = (UWord)ciii.intregs37[17]; |
| 325 | arch->vex.guest_GPR18 = (UWord)ciii.intregs37[18]; |
| 326 | arch->vex.guest_GPR19 = (UWord)ciii.intregs37[19]; |
| 327 | arch->vex.guest_GPR20 = (UWord)ciii.intregs37[20]; |
| 328 | arch->vex.guest_GPR21 = (UWord)ciii.intregs37[21]; |
| 329 | arch->vex.guest_GPR22 = (UWord)ciii.intregs37[22]; |
| 330 | arch->vex.guest_GPR23 = (UWord)ciii.intregs37[23]; |
| 331 | arch->vex.guest_GPR24 = (UWord)ciii.intregs37[24]; |
| 332 | arch->vex.guest_GPR25 = (UWord)ciii.intregs37[25]; |
| 333 | arch->vex.guest_GPR26 = (UWord)ciii.intregs37[26]; |
| 334 | arch->vex.guest_GPR27 = (UWord)ciii.intregs37[27]; |
| 335 | arch->vex.guest_GPR28 = (UWord)ciii.intregs37[28]; |
| 336 | arch->vex.guest_GPR29 = (UWord)ciii.intregs37[29]; |
| 337 | arch->vex.guest_GPR30 = (UWord)ciii.intregs37[30]; |
| 338 | arch->vex.guest_GPR31 = (UWord)ciii.intregs37[31]; |
| 339 | |
| 340 | arch->vex.guest_CIA = (UWord)ciii.intregs37[32+0]; |
| 341 | arch->vex.guest_LR = (UWord)ciii.intregs37[32+2]; |
| 342 | arch->vex.guest_CTR = (UWord)ciii.intregs37[32+3]; |
| 343 | |
| 344 | # if defined(VGP_ppc32_aix5) |
| 345 | |
| 346 | LibVEX_GuestPPC32_put_CR( (UWord)ciii.intregs37[32+1], &arch->vex ); |
| 347 | LibVEX_GuestPPC32_put_XER( (UWord)ciii.intregs37[32+4], &arch->vex ); |
| 348 | |
| 349 | /* Set the cache line size (KLUDGE) */ |
| 350 | VG_(machine_ppc32_set_clszB)( 128 ); |
| 351 | |
| 352 | # else /* defined(VGP_ppc64_aix5) */ |
| 353 | |
| 354 | LibVEX_GuestPPC64_put_CR( (UWord)ciii.intregs37[32+1], &arch->vex ); |
| 355 | LibVEX_GuestPPC64_put_XER( (UWord)ciii.intregs37[32+4], &arch->vex ); |
| 356 | |
| 357 | /* Set the cache line size (KLUDGE) */ |
| 358 | VG_(machine_ppc64_set_clszB)( 128 ); |
| 359 | |
| 360 | # endif |
| 361 | |
| 362 | /* Fix up the client's command line. Its argc/v/envp is in r3/4/5 |
| 363 | (32-bit AIX) or r14/15/16 (64-bit AIX). but that is for the |
| 364 | Valgrind invokation as a whole. Hence we need to decrement argc |
| 365 | and advance argv to step over the args for Valgrind, and the |
| 366 | name of the Valgrind tool exe bogusly inserted by the launcher |
| 367 | (hence the "+1"). */ |
| 368 | |
| 369 | # if defined(VGP_ppc32_aix5) |
| 370 | |
| 371 | vg_assert(arch->vex.guest_GPR3 >= 1 + VG_(args_for_valgrind).used); |
| 372 | arch->vex.guest_GPR3 -= (1 + VG_(args_for_valgrind).used); |
| 373 | arch->vex.guest_GPR4 += sizeof(UWord) * (1 + VG_(args_for_valgrind).used); |
| 374 | |
| 375 | # else /* defined(VGP_ppc64_aix5) */ |
| 376 | |
| 377 | vg_assert(arch->vex.guest_GPR14 >= 1 + VG_(args_for_valgrind).used); |
| 378 | arch->vex.guest_GPR14 -= (1 + VG_(args_for_valgrind).used); |
| 379 | arch->vex.guest_GPR15 += sizeof(UWord) * (1 + VG_(args_for_valgrind).used); |
| 380 | |
| 381 | # endif |
| 382 | |
| 383 | /* At this point the guest register state is correct for client |
| 384 | startup. However, that's not where we want to start; in fact we |
| 385 | want to start at VG_(ppc{3,64}2_aix5_do_preloads_then_start_client), |
| 386 | passing it ciii.preloadpage in r3. This will load the core/tool |
| 387 | preload .so's, then restore r2-r10 from what's stashed in the |
| 388 | preloadpage, and then start the client really. Hence: */ |
| 389 | |
| 390 | /* Save r2-r10 and the client start point in preloadpage */ |
| 391 | ciii.preloadpage->r2 = (ULong)arch->vex.guest_GPR2; |
| 392 | ciii.preloadpage->r3 = (ULong)arch->vex.guest_GPR3; |
| 393 | ciii.preloadpage->r4 = (ULong)arch->vex.guest_GPR4; |
| 394 | ciii.preloadpage->r5 = (ULong)arch->vex.guest_GPR5; |
| 395 | ciii.preloadpage->r6 = (ULong)arch->vex.guest_GPR6; |
| 396 | ciii.preloadpage->r7 = (ULong)arch->vex.guest_GPR7; |
| 397 | ciii.preloadpage->r8 = (ULong)arch->vex.guest_GPR8; |
| 398 | ciii.preloadpage->r9 = (ULong)arch->vex.guest_GPR9; |
| 399 | ciii.preloadpage->r10 = (ULong)arch->vex.guest_GPR10; |
| 400 | ciii.preloadpage->client_start = (ULong)arch->vex.guest_CIA; |
| 401 | |
| 402 | |
| 403 | # if defined(VGP_ppc32_aix5) |
| 404 | |
| 405 | /* Set up to start at VG_(ppc32_aix5_do_preloads_then_start_client) */ |
| 406 | arch->vex.guest_CIA = (UWord)&VG_(ppc32_aix5_do_preloads_then_start_client); |
| 407 | |
| 408 | # else /* defined(VGP_ppc64_aix5) */ |
| 409 | |
| 410 | /* Set up to start at VG_(ppc64_aix5_do_preloads_then_start_client) */ |
| 411 | arch->vex.guest_CIA = (UWord)&VG_(ppc64_aix5_do_preloads_then_start_client); |
| 412 | |
| 413 | # endif |
| 414 | |
| 415 | arch->vex.guest_GPR3 = (UWord)ciii.preloadpage; |
| 416 | |
| 417 | /* The rest of the preloadpage fields will already have been filled |
| 418 | in by VG_(setup_client_initial_image). So we're done. */ |
| 419 | |
| 420 | /* Finally, decompress the page compressed by the launcher. We |
| 421 | can't do this any earlier, because the page is (effectively) |
| 422 | decompressed in place, which trashes ciii.intregs37. So we have |
| 423 | to wait till this point, at which we're done with ciii.intregs37 |
| 424 | (to be precise, with what it points at). */ |
| 425 | VG_(debugLog)(1, "initimg", "decompressing page at %p\n", |
| 426 | (void*)ciii.compressed_page); |
| 427 | vg_assert(VG_IS_PAGE_ALIGNED(ciii.compressed_page)); |
| 428 | |
| 429 | Huffman_Uncompress( (void*)ciii.compressed_page, unz_page, |
| 430 | VKI_PAGE_SIZE, VKI_PAGE_SIZE ); |
| 431 | adler32_act = compute_adler32(unz_page, VKI_PAGE_SIZE); |
| 432 | |
| 433 | VG_(debugLog)(1, "initimg", |
| 434 | "decompress done, adler32s: act 0x%x, exp 0x%x\n", |
| 435 | adler32_act, ciii.adler32_exp ); |
| 436 | |
| 437 | VG_(memcpy)((void*)ciii.compressed_page, unz_page, VKI_PAGE_SIZE); |
| 438 | |
| 439 | VG_(debugLog)(1, "initimg", "copy back done\n"); |
| 440 | |
| 441 | /* Tell the tool that we just wrote to the registers. */ |
| 442 | VG_TRACK( post_reg_write, Vg_CoreStartup, /*tid*/1, /*offset*/0, |
| 443 | sizeof(VexGuestArchState)); |
| 444 | |
| 445 | /* Determine the brk limit. */ |
| 446 | VG_(debugLog)(1, "initimg", "establishing current brk ..\n"); |
| 447 | vg_assert(__NR_AIX5_sbrk != __NR_AIX5_UNKNOWN); |
| 448 | sres = VG_(do_syscall1)(__NR_AIX5_sbrk, 0); |
| 449 | vg_assert(sres.err == 0); /* assert no error */ |
| 450 | VG_(brk_base) = VG_(brk_limit) = sres.res; |
| 451 | VG_(debugLog)(1, "initimg", ".. brk = %p\n", (void*)VG_(brk_base)); |
| 452 | } |
| 453 | |
| 454 | |
| 455 | /* --- Diagnose preload failures. --- */ |
| 456 | |
| 457 | /* This is a nasty but effective kludge. The address of the following |
| 458 | function is put into the preload page. So, if a preload failure |
| 459 | happens, we call here to get helpful info printed out (the call |
| 460 | site is in m_trampoline.S). This is a dirty hack (1) because |
| 461 | diagnose_load_failure runs on the simulated CPU, not the real one |
| 462 | and (2) because it induces a libc dependency. Oh well. */ |
| 463 | |
| 464 | /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */ |
| 465 | #include <stdlib.h> |
| 466 | #include <sys/ldr.h> |
| 467 | /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */ |
| 468 | |
| 469 | static void diagnose_load_failure ( void ) |
| 470 | { |
| 471 | # define NBUF 1024 |
| 472 | UChar buf[NBUF]; |
| 473 | VG_(debugLog)(0, "initimg", "Diagnosing load failure\n"); |
| 474 | if (sizeof(void*) == 8) { |
| 475 | VG_(debugLog)(0, "initimg", "Can't safely do loadquery() " |
| 476 | "in 64-bit mode. Sorry.\n"); |
| 477 | /* because this requires dynamic linking to be working (IIRC) |
| 478 | and it isn't; the tool file's dynamic linking was never done, |
| 479 | because it was loaded by the bootstrap stub, which simply did |
| 480 | sys_kload() but didn't make usla do the relevant |
| 481 | relocations. */ |
| 482 | } else { |
| 483 | UChar** p; |
| 484 | Int r = loadquery(L_GETMESSAGES, buf, NBUF); |
| 485 | VG_(debugLog)(0, "initimg", "loadquery returned %d (0 = success)\n", r); |
| 486 | p = (UChar**)(&buf[0]); |
| 487 | for (; *p; p++) |
| 488 | VG_(debugLog)(0, "initimg", "\"%s\"\n", *p); |
| 489 | VG_(debugLog)(0, "initimg", "Use /usr/sbin/execerror to make " |
| 490 | "sense of above string(s)\n"); |
| 491 | VG_(debugLog)(0, "initimg", "See also comments at the bottom of\n"); |
| 492 | VG_(debugLog)(0, "initimg", "coregrind/m_initimg/" |
| 493 | "initimg-aix5.c (in Valgrind sources)\n"); |
| 494 | } |
| 495 | # undef NBUF |
| 496 | } |
| 497 | |
| 498 | /* Take the strings that this prints out and feed them |
| 499 | to /usr/sbin/execerror. For example, it might print |
| 500 | |
| 501 | (ld 3 1 __libc_freeres /foo/bar/ppc32-aix5/vgpreload_core.so |
| 502 | |
| 503 | in which case |
| 504 | |
| 505 | $ execerror xyzzy \ |
| 506 | "(ld 3 1 __libc_freeres /foo/bar/ppc32-aix5/vgpreload_core.so" |
| 507 | |
| 508 | gets you |
| 509 | |
| 510 | Could not load program xyzzy: |
| 511 | rtld: 0712-001 Symbol __libc_freeres was referenced |
| 512 | from module /foo/bar/ppc32-aix5/vgpreload_core.so(), |
| 513 | but a runtime definition |
| 514 | of the symbol was not found. |
| 515 | */ |
| 516 | |
| 517 | /*--------------------------------------------------------------------*/ |
| 518 | /*--- initimg-aix5.c ---*/ |
| 519 | /*--------------------------------------------------------------------*/ |