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