src/os/aix/vm/porting_aix.cpp

changeset 6465
666e6ce3976c
parent 0
f90c822e73f8
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/os/aix/vm/porting_aix.cpp	Fri Sep 06 20:16:09 2013 +0200
     1.3 @@ -0,0 +1,367 @@
     1.4 +/*
     1.5 + * Copyright 2012, 2013 SAP AG. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.23 + * or visit www.oracle.com if you need additional information or have any
    1.24 + * questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +#include "asm/assembler.hpp"
    1.29 +#include "loadlib_aix.hpp"
    1.30 +#include "porting_aix.hpp"
    1.31 +#include "utilities/debug.hpp"
    1.32 +
    1.33 +#include <demangle.h>
    1.34 +#include <sys/debug.h>
    1.35 +
    1.36 +//////////////////////////////////
    1.37 +// Provide implementation for dladdr based on LoadedLibraries pool and
    1.38 +// traceback table scan (see getFuncName).
    1.39 +
    1.40 +// Search traceback table in stack,
    1.41 +// return procedure name from trace back table.
    1.42 +#define MAX_FUNC_SEARCH_LEN 0x10000
    1.43 +// Any PC below this value is considered toast.
    1.44 +#define MINIMUM_VALUE_FOR_PC ((unsigned int*)0x1024)
    1.45 +
    1.46 +#define PTRDIFF_BYTES(p1,p2) (((ptrdiff_t)p1) - ((ptrdiff_t)p2))
    1.47 +
    1.48 +// Align a pointer without having to cast.
    1.49 +inline char* align_ptr_up(char* ptr, intptr_t alignment) {
    1.50 +  return (char*) align_size_up((intptr_t)ptr, alignment);
    1.51 +}
    1.52 +
    1.53 +// Trace if verbose to tty.
    1.54 +// I use these now instead of the Xtrace system because the latter is
    1.55 +// not available at init time, hence worthless. Until we fix this, all
    1.56 +// tracing here is done with -XX:+Verbose.
    1.57 +#define trcVerbose(fmt, ...) { \
    1.58 +  if (Verbose) { \
    1.59 +    fprintf(stderr, fmt, ##__VA_ARGS__); \
    1.60 +    fputc('\n', stderr); fflush(stderr); \
    1.61 +  } \
    1.62 +}
    1.63 +#define ERRBYE(s) { trcVerbose(s); return -1; }
    1.64 +
    1.65 +// Unfortunately, the interface of dladdr makes the implementator
    1.66 +// responsible for maintaining memory for function name/library
    1.67 +// name. I guess this is because most OS's keep those values as part
    1.68 +// of the mapped executable image ready to use. On AIX, this doesn't
    1.69 +// work, so I have to keep the returned strings. For now, I do this in
    1.70 +// a primitive string map. Should this turn out to be a performance
    1.71 +// problem, a better hashmap has to be used.
    1.72 +class fixed_strings {
    1.73 +  struct node {
    1.74 +    char* v;
    1.75 +    node* next;
    1.76 +  };
    1.77 +
    1.78 +  node* first;
    1.79 +
    1.80 +  public:
    1.81 +
    1.82 +  fixed_strings() : first(0) {}
    1.83 +  ~fixed_strings() {
    1.84 +    node* n = first;
    1.85 +    while (n) {
    1.86 +      node* p = n;
    1.87 +      n = n->next;
    1.88 +      free(p->v);
    1.89 +      delete p;
    1.90 +    }
    1.91 +  }
    1.92 +
    1.93 +  char* intern(const char* s) {
    1.94 +    for (node* n = first; n; n = n->next) {
    1.95 +      if (strcmp(n->v, s) == 0) {
    1.96 +        return n->v;
    1.97 +      }
    1.98 +    }
    1.99 +    node* p = new node;
   1.100 +    p->v = strdup(s);
   1.101 +    p->next = first;
   1.102 +    first = p;
   1.103 +    return p->v;
   1.104 +  }
   1.105 +};
   1.106 +
   1.107 +static fixed_strings dladdr_fixed_strings;
   1.108 +
   1.109 +// Given a code pointer, returns the function name and the displacement.
   1.110 +// Function looks for the traceback table at the end of the function.
   1.111 +extern "C" int getFuncName(
   1.112 +    codeptr_t pc,                    // [in] program counter
   1.113 +    char* p_name, size_t namelen,    // [out] optional: function name ("" if not available)
   1.114 +    int* p_displacement,             // [out] optional: displacement (-1 if not available)
   1.115 +    const struct tbtable** p_tb,     // [out] optional: ptr to traceback table to get further
   1.116 +                                     //                 information (NULL if not available)
   1.117 +    char* p_errmsg, size_t errmsglen // [out] optional: user provided buffer for error messages
   1.118 +  ) {
   1.119 +  struct tbtable* tb = 0;
   1.120 +  unsigned int searchcount = 0;
   1.121 +
   1.122 +  // initialize output parameters
   1.123 +  if (p_name && namelen > 0) {
   1.124 +    *p_name = '\0';
   1.125 +  }
   1.126 +  if (p_errmsg && errmsglen > 0) {
   1.127 +    *p_errmsg = '\0';
   1.128 +  }
   1.129 +  if (p_displacement) {
   1.130 +    *p_displacement = -1;
   1.131 +  }
   1.132 +  if (p_tb) {
   1.133 +    *p_tb = NULL;
   1.134 +  }
   1.135 +
   1.136 +  // weed out obvious bogus states
   1.137 +  if (pc < MINIMUM_VALUE_FOR_PC) {
   1.138 +    ERRBYE("invalid program counter");
   1.139 +  }
   1.140 +
   1.141 +  codeptr_t pc2 = pc;
   1.142 +
   1.143 +  // make sure the pointer is word aligned.
   1.144 +  pc2 = (codeptr_t) align_ptr_up((char*)pc2, 4);
   1.145 +
   1.146 +  // Find start of traceback table.
   1.147 +  // (starts after code, is marked by word-aligned (32bit) zeros)
   1.148 +  while ((*pc2 != NULL) && (searchcount++ < MAX_FUNC_SEARCH_LEN)) {
   1.149 +    pc2++;
   1.150 +  }
   1.151 +  if (*pc2 != 0) {
   1.152 +    ERRBYE("could not find traceback table within 5000 bytes of program counter");
   1.153 +  }
   1.154 +  //
   1.155 +  // Set up addressability to the traceback table
   1.156 +  //
   1.157 +  tb = (struct tbtable*) (pc2 + 1);
   1.158 +
   1.159 +  // Is this really a traceback table? No way to be sure but
   1.160 +  // some indicators we can check.
   1.161 +  if (tb->tb.lang >= 0xf && tb->tb.lang <= 0xfb) {
   1.162 +    // Language specifiers, go from 0 (C) to 14 (Objective C).
   1.163 +    // According to spec, 0xf-0xfa reserved, 0xfb-0xff reserved for ibm.
   1.164 +    ERRBYE("not a traceback table");
   1.165 +  }
   1.166 +
   1.167 +  // Existence of fields in the tbtable extension are contingent upon
   1.168 +  // specific fields in the base table.  Check for their existence so
   1.169 +  // that we can address the function name if it exists.
   1.170 +  pc2 = (codeptr_t) tb +
   1.171 +    sizeof(struct tbtable_short)/sizeof(int);
   1.172 +  if (tb->tb.fixedparms != 0 || tb->tb.floatparms != 0)
   1.173 +    pc2++;
   1.174 +
   1.175 +  if (tb->tb.has_tboff == TRUE) {
   1.176 +
   1.177 +    // I want to know the displacement
   1.178 +    const unsigned int tb_offset = *pc2;
   1.179 +    codeptr_t start_of_procedure =
   1.180 +    (codeptr_t)(((char*)tb) - 4 - tb_offset);  // (-4 to omit leading 0000)
   1.181 +
   1.182 +    // Weed out the cases where we did find the wrong traceback table.
   1.183 +    if (pc < start_of_procedure) {
   1.184 +      ERRBYE("could not find (the real) traceback table within 5000 bytes of program counter");
   1.185 +    }
   1.186 +
   1.187 +    // return the displacement
   1.188 +    if (p_displacement) {
   1.189 +      (*p_displacement) = (int) PTRDIFF_BYTES(pc, start_of_procedure);
   1.190 +    }
   1.191 +
   1.192 +    pc2++;
   1.193 +  } else {
   1.194 +    // return -1 for displacement
   1.195 +    if (p_displacement) {
   1.196 +      (*p_displacement) = -1;
   1.197 +    }
   1.198 +  }
   1.199 +
   1.200 +  if (tb->tb.int_hndl == TRUE)
   1.201 +    pc2++;
   1.202 +
   1.203 +  if (tb->tb.has_ctl == TRUE)
   1.204 +    pc2 += (*pc2) + 1; // don't care
   1.205 +
   1.206 +  //
   1.207 +  // return function name if it exists.
   1.208 +  //
   1.209 +  if (p_name && namelen > 0) {
   1.210 +    if (tb->tb.name_present) {
   1.211 +      char buf[256];
   1.212 +      const short l = MIN2<short>(*((short*)pc2), sizeof(buf) - 1);
   1.213 +      memcpy(buf, (char*)pc2 + sizeof(short), l);
   1.214 +      buf[l] = '\0';
   1.215 +
   1.216 +      p_name[0] = '\0';
   1.217 +
   1.218 +      // If it is a C++ name, try and demangle it using the Demangle interface (see demangle.h).
   1.219 +      char* rest;
   1.220 +      Name* const name = Demangle(buf, rest);
   1.221 +      if (name) {
   1.222 +        const char* const demangled_name = name->Text();
   1.223 +        if (demangled_name) {
   1.224 +          strncpy(p_name, demangled_name, namelen-1);
   1.225 +          p_name[namelen-1] = '\0';
   1.226 +        }
   1.227 +        delete name;
   1.228 +      }
   1.229 +
   1.230 +      // Fallback: if demangling did not work, just provide the unmangled name.
   1.231 +      if (p_name[0] == '\0') {
   1.232 +        strncpy(p_name, buf, namelen-1);
   1.233 +        p_name[namelen-1] = '\0';
   1.234 +      }
   1.235 +
   1.236 +    } else {
   1.237 +      strncpy(p_name, "<nameless function>", namelen-1);
   1.238 +      p_name[namelen-1] = '\0';
   1.239 +    }
   1.240 +  }
   1.241 +  // Return traceback table, if user wants it.
   1.242 +  if (p_tb) {
   1.243 +    (*p_tb) = tb;
   1.244 +  }
   1.245 +
   1.246 +  return 0;
   1.247 +}
   1.248 +
   1.249 +// Special implementation of dladdr for Aix based on LoadedLibraries
   1.250 +// Note: dladdr returns non-zero for ok, 0 for error!
   1.251 +// Note: dladdr is not posix, but a non-standard GNU extension. So this tries to
   1.252 +//   fulfill the contract of dladdr on Linux (see http://linux.die.net/man/3/dladdr)
   1.253 +// Note: addr may be both an AIX function descriptor or a real code pointer
   1.254 +//   to the entry of a function.
   1.255 +extern "C"
   1.256 +int dladdr(void* addr, Dl_info* info) {
   1.257 +
   1.258 +  if (!addr) {
   1.259 +    return 0;
   1.260 +  }
   1.261 +
   1.262 +  assert(info, "");
   1.263 +
   1.264 +  int rc = 0;
   1.265 +
   1.266 +  const char* const ZEROSTRING = "";
   1.267 +
   1.268 +  // Always return a string, even if a "" one. Linux dladdr manpage
   1.269 +  // does not say anything about returning NULL
   1.270 +  info->dli_fname = ZEROSTRING;
   1.271 +  info->dli_sname = ZEROSTRING;
   1.272 +  info->dli_saddr = NULL;
   1.273 +
   1.274 +  address p = (address) addr;
   1.275 +  const LoadedLibraryModule* lib = NULL;
   1.276 +
   1.277 +  enum { noclue, code, data } type = noclue;
   1.278 +
   1.279 +  trcVerbose("dladdr(%p)...", p);
   1.280 +
   1.281 +  // Note: input address may be a function. I accept both a pointer to
   1.282 +  // the entry of a function and a pointer to the function decriptor.
   1.283 +  // (see ppc64 ABI)
   1.284 +  lib = LoadedLibraries::find_for_text_address(p);
   1.285 +  if (lib) {
   1.286 +    type = code;
   1.287 +  }
   1.288 +
   1.289 +  if (!lib) {
   1.290 +    // Not a pointer into any text segment. Is it a function descriptor?
   1.291 +    const FunctionDescriptor* const pfd = (const FunctionDescriptor*) p;
   1.292 +    p = pfd->entry();
   1.293 +    if (p) {
   1.294 +      lib = LoadedLibraries::find_for_text_address(p);
   1.295 +      if (lib) {
   1.296 +        type = code;
   1.297 +      }
   1.298 +    }
   1.299 +  }
   1.300 +
   1.301 +  if (!lib) {
   1.302 +    // Neither direct code pointer nor function descriptor. A data ptr?
   1.303 +    p = (address)addr;
   1.304 +    lib = LoadedLibraries::find_for_data_address(p);
   1.305 +    if (lib) {
   1.306 +      type = data;
   1.307 +    }
   1.308 +  }
   1.309 +
   1.310 +  // If we did find the shared library this address belongs to (either
   1.311 +  // code or data segment) resolve library path and, if possible, the
   1.312 +  // symbol name.
   1.313 +  if (lib) {
   1.314 +    const char* const interned_libpath =
   1.315 +      dladdr_fixed_strings.intern(lib->get_fullpath());
   1.316 +    if (interned_libpath) {
   1.317 +      info->dli_fname = interned_libpath;
   1.318 +    }
   1.319 +
   1.320 +    if (type == code) {
   1.321 +
   1.322 +      // For code symbols resolve function name and displacement. Use
   1.323 +      // displacement to calc start of function.
   1.324 +      char funcname[256] = "";
   1.325 +      int displacement = 0;
   1.326 +
   1.327 +      if (getFuncName((codeptr_t) p, funcname, sizeof(funcname), &displacement,
   1.328 +                      NULL, NULL, 0) == 0) {
   1.329 +        if (funcname[0] != '\0') {
   1.330 +          const char* const interned = dladdr_fixed_strings.intern(funcname);
   1.331 +          info->dli_sname = interned;
   1.332 +          trcVerbose("... function name: %s ...", interned);
   1.333 +        }
   1.334 +
   1.335 +        // From the displacement calculate the start of the function.
   1.336 +        if (displacement != -1) {
   1.337 +          info->dli_saddr = p - displacement;
   1.338 +        } else {
   1.339 +          info->dli_saddr = p;
   1.340 +        }
   1.341 +      } else {
   1.342 +
   1.343 +        // No traceback table found. Just assume the pointer is it.
   1.344 +        info->dli_saddr = p;
   1.345 +
   1.346 +      }
   1.347 +
   1.348 +    } else if (type == data) {
   1.349 +
   1.350 +      // For data symbols.
   1.351 +      info->dli_saddr = p;
   1.352 +
   1.353 +    } else {
   1.354 +      ShouldNotReachHere();
   1.355 +    }
   1.356 +
   1.357 +    rc = 1; // success: return 1 [sic]
   1.358 +
   1.359 +  }
   1.360 +
   1.361 +  // sanity checks.
   1.362 +  if (rc) {
   1.363 +    assert(info->dli_fname, "");
   1.364 +    assert(info->dli_sname, "");
   1.365 +    assert(info->dli_saddr, "");
   1.366 +  }
   1.367 +
   1.368 +  return rc; // error: return 0 [sic]
   1.369 +
   1.370 +}

mercurial