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