agent/src/os/bsd/ps_core.c

changeset 5832
5705c7ee6dd7
parent 5061
f6a055fcf47d
child 6876
710a3c8b516e
     1.1 --- a/agent/src/os/bsd/ps_core.c	Tue Oct 01 15:41:39 2013 -0400
     1.2 +++ b/agent/src/os/bsd/ps_core.c	Wed Oct 02 22:27:23 2013 +0400
     1.3 @@ -44,6 +44,7 @@
     1.4  // close all file descriptors
     1.5  static void close_files(struct ps_prochandle* ph) {
     1.6    lib_info* lib = NULL;
     1.7 +
     1.8    // close core file descriptor
     1.9    if (ph->core->core_fd >= 0)
    1.10      close(ph->core->core_fd);
    1.11 @@ -149,8 +150,7 @@
    1.12  
    1.13  // Return the map_info for the given virtual address.  We keep a sorted
    1.14  // array of pointers in ph->map_array, so we can binary search.
    1.15 -static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr)
    1.16 -{
    1.17 +static map_info* core_lookup(struct ps_prochandle *ph, uintptr_t addr) {
    1.18    int mid, lo = 0, hi = ph->core->num_maps - 1;
    1.19    map_info *mp;
    1.20  
    1.21 @@ -230,9 +230,9 @@
    1.22      size_t _used;            // for setting space top on read
    1.23  
    1.24      // 4991491 NOTICE These are C++ bool's in filemap.hpp and must match up with
    1.25 -    // the C type matching the C++ bool type on any given platform. For
    1.26 -    // Hotspot on BSD we assume the corresponding C type is char but
    1.27 -    // licensees on BSD versions may need to adjust the type of these fields.
    1.28 +    // the C type matching the C++ bool type on any given platform.
    1.29 +    // We assume the corresponding C type is char but licensees
    1.30 +    // may need to adjust the type of these fields.
    1.31      char   _read_only;       // read only space?
    1.32      char   _allow_exec;      // executable code in space?
    1.33  
    1.34 @@ -286,10 +286,12 @@
    1.35  #define USE_SHARED_SPACES_SYM "_UseSharedSpaces"
    1.36  // mangled name of Arguments::SharedArchivePath
    1.37  #define SHARED_ARCHIVE_PATH_SYM "_ZN9Arguments17SharedArchivePathE"
    1.38 +#define LIBJVM_NAME "/libjvm.dylib"
    1.39  #else
    1.40  #define USE_SHARED_SPACES_SYM "UseSharedSpaces"
    1.41  // mangled name of Arguments::SharedArchivePath
    1.42  #define SHARED_ARCHIVE_PATH_SYM "__ZN9Arguments17SharedArchivePathE"
    1.43 +#define LIBJVM_NAME "/libjvm.so"
    1.44  #endif // __APPLE_
    1.45  
    1.46  static bool init_classsharing_workaround(struct ps_prochandle* ph) {
    1.47 @@ -300,12 +302,7 @@
    1.48      // we are iterating over shared objects from the core dump. look for
    1.49      // libjvm.so.
    1.50      const char *jvm_name = 0;
    1.51 -#ifdef __APPLE__
    1.52 -    if ((jvm_name = strstr(lib->name, "/libjvm.dylib")) != 0)
    1.53 -#else
    1.54 -    if ((jvm_name = strstr(lib->name, "/libjvm.so")) != 0)
    1.55 -#endif // __APPLE__
    1.56 -    {
    1.57 +    if ((jvm_name = strstr(lib->name, LIBJVM_NAME)) != 0) {
    1.58        char classes_jsa[PATH_MAX];
    1.59        struct FileMapHeader header;
    1.60        int fd = -1;
    1.61 @@ -399,8 +396,8 @@
    1.62          }
    1.63        }
    1.64        return true;
    1.65 -    }
    1.66 -    lib = lib->next;
    1.67 +   }
    1.68 +   lib = lib->next;
    1.69    }
    1.70    return true;
    1.71  }
    1.72 @@ -432,8 +429,8 @@
    1.73    // allocate map_array
    1.74    map_info** array;
    1.75    if ( (array = (map_info**) malloc(sizeof(map_info*) * num_maps)) == NULL) {
    1.76 -     print_debug("can't allocate memory for map array\n");
    1.77 -     return false;
    1.78 +    print_debug("can't allocate memory for map array\n");
    1.79 +    return false;
    1.80    }
    1.81  
    1.82    // add maps to array
    1.83 @@ -450,7 +447,7 @@
    1.84    ph->core->map_array = array;
    1.85    // sort the map_info array by base virtual address.
    1.86    qsort(ph->core->map_array, ph->core->num_maps, sizeof (map_info*),
    1.87 -           core_cmp_mapping);
    1.88 +        core_cmp_mapping);
    1.89  
    1.90    // print map
    1.91    if (is_debug()) {
    1.92 @@ -458,7 +455,7 @@
    1.93      print_debug("---- sorted virtual address map ----\n");
    1.94      for (j = 0; j < ph->core->num_maps; j++) {
    1.95        print_debug("base = 0x%lx\tsize = %d\n", ph->core->map_array[j]->vaddr,
    1.96 -                                       ph->core->map_array[j]->memsz);
    1.97 +                  ph->core->map_array[j]->memsz);
    1.98      }
    1.99    }
   1.100  
   1.101 @@ -1091,9 +1088,9 @@
   1.102                                     notep->n_type, notep->n_descsz);
   1.103  
   1.104        if (notep->n_type == NT_PRSTATUS) {
   1.105 -         if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) {
   1.106 -            return false;
   1.107 -         }
   1.108 +        if (core_handle_prstatus(ph, descdata, notep->n_descsz) != true) {
   1.109 +          return false;
   1.110 +        }
   1.111        }
   1.112        p = descdata + ROUNDUP(notep->n_descsz, 4);
   1.113     }
   1.114 @@ -1121,7 +1118,7 @@
   1.115      * contains a set of saved /proc structures), and PT_LOAD (which
   1.116      * represents a memory mapping from the process's address space).
   1.117      *
   1.118 -    * Difference b/w Solaris PT_NOTE and BSD PT_NOTE:
   1.119 +    * Difference b/w Solaris PT_NOTE and Linux/BSD PT_NOTE:
   1.120      *
   1.121      *     In Solaris there are two PT_NOTE segments the first PT_NOTE (if present)
   1.122      *     contains /proc structs in the pre-2.6 unstructured /proc format. the last
   1.123 @@ -1167,32 +1164,61 @@
   1.124  
   1.125  // read segments of a shared object
   1.126  static bool read_lib_segments(struct ps_prochandle* ph, int lib_fd, ELF_EHDR* lib_ehdr, uintptr_t lib_base) {
   1.127 -   int i = 0;
   1.128 -   ELF_PHDR* phbuf;
   1.129 -   ELF_PHDR* lib_php = NULL;
   1.130 +  int i = 0;
   1.131 +  ELF_PHDR* phbuf;
   1.132 +  ELF_PHDR* lib_php = NULL;
   1.133  
   1.134 -   if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL)
   1.135 -      return false;
   1.136 +  int page_size=sysconf(_SC_PAGE_SIZE);
   1.137  
   1.138 -   // we want to process only PT_LOAD segments that are not writable.
   1.139 -   // i.e., text segments. The read/write/exec (data) segments would
   1.140 -   // have been already added from core file segments.
   1.141 -   for (lib_php = phbuf, i = 0; i < lib_ehdr->e_phnum; i++) {
   1.142 -      if ((lib_php->p_type == PT_LOAD) && !(lib_php->p_flags & PF_W) && (lib_php->p_filesz != 0)) {
   1.143 -         if (add_map_info(ph, lib_fd, lib_php->p_offset, lib_php->p_vaddr + lib_base, lib_php->p_filesz) == NULL)
   1.144 -            goto err;
   1.145 +  if ((phbuf = read_program_header_table(lib_fd, lib_ehdr)) == NULL) {
   1.146 +    return false;
   1.147 +  }
   1.148 +
   1.149 +  // we want to process only PT_LOAD segments that are not writable.
   1.150 +  // i.e., text segments. The read/write/exec (data) segments would
   1.151 +  // have been already added from core file segments.
   1.152 +  for (lib_php = phbuf, i = 0; i < lib_ehdr->e_phnum; i++) {
   1.153 +    if ((lib_php->p_type == PT_LOAD) && !(lib_php->p_flags & PF_W) && (lib_php->p_filesz != 0)) {
   1.154 +
   1.155 +      uintptr_t target_vaddr = lib_php->p_vaddr + lib_base;
   1.156 +      map_info *existing_map = core_lookup(ph, target_vaddr);
   1.157 +
   1.158 +      if (existing_map == NULL){
   1.159 +        if (add_map_info(ph, lib_fd, lib_php->p_offset,
   1.160 +                          target_vaddr, lib_php->p_filesz) == NULL) {
   1.161 +          goto err;
   1.162 +        }
   1.163 +      } else {
   1.164 +        if ((existing_map->memsz != page_size) &&
   1.165 +            (existing_map->fd != lib_fd) &&
   1.166 +            (existing_map->memsz != lib_php->p_filesz)){
   1.167 +
   1.168 +          print_debug("address conflict @ 0x%lx (size = %ld, flags = %d\n)",
   1.169 +                        target_vaddr, lib_php->p_filesz, lib_php->p_flags);
   1.170 +          goto err;
   1.171 +        }
   1.172 +
   1.173 +        /* replace PT_LOAD segment with library segment */
   1.174 +        print_debug("overwrote with new address mapping (memsz %ld -> %ld)\n",
   1.175 +                     existing_map->memsz, lib_php->p_filesz);
   1.176 +
   1.177 +        existing_map->fd = lib_fd;
   1.178 +        existing_map->offset = lib_php->p_offset;
   1.179 +        existing_map->memsz = lib_php->p_filesz;
   1.180        }
   1.181 -      lib_php++;
   1.182 -   }
   1.183 +    }
   1.184  
   1.185 -   free(phbuf);
   1.186 -   return true;
   1.187 +    lib_php++;
   1.188 +  }
   1.189 +
   1.190 +  free(phbuf);
   1.191 +  return true;
   1.192  err:
   1.193 -   free(phbuf);
   1.194 -   return false;
   1.195 +  free(phbuf);
   1.196 +  return false;
   1.197  }
   1.198  
   1.199 -// process segments from interpreter (ld-elf.so.1)
   1.200 +// process segments from interpreter (ld.so or ld-linux.so or ld-elf.so)
   1.201  static bool read_interp_segments(struct ps_prochandle* ph) {
   1.202     ELF_EHDR interp_ehdr;
   1.203  
   1.204 @@ -1303,32 +1329,34 @@
   1.205    debug_base = dyn.d_un.d_ptr;
   1.206    // at debug_base we have struct r_debug. This has first link map in r_map field
   1.207    if (ps_pread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET,
   1.208 -                  &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) {
   1.209 +                 &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) {
   1.210      print_debug("can't read first link map address\n");
   1.211      return false;
   1.212    }
   1.213  
   1.214    // read ld_base address from struct r_debug
   1.215 -  // XXX: There is no r_ldbase member on BSD
   1.216 -  /*
   1.217 +#if 0  // There is no r_ldbase member on BSD
   1.218    if (ps_pread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr,
   1.219                    sizeof(uintptr_t)) != PS_OK) {
   1.220      print_debug("can't read ld base address\n");
   1.221      return false;
   1.222    }
   1.223    ph->core->ld_base_addr = ld_base_addr;
   1.224 -  */
   1.225 +#else
   1.226    ph->core->ld_base_addr = 0;
   1.227 +#endif
   1.228  
   1.229    print_debug("interpreter base address is 0x%lx\n", ld_base_addr);
   1.230  
   1.231 -  // now read segments from interp (i.e ld-elf.so.1)
   1.232 -  if (read_interp_segments(ph) != true)
   1.233 +  // now read segments from interp (i.e ld.so or ld-linux.so or ld-elf.so)
   1.234 +  if (read_interp_segments(ph) != true) {
   1.235      return false;
   1.236 +  }
   1.237  
   1.238    // after adding interpreter (ld.so) mappings sort again
   1.239 -  if (sort_map_array(ph) != true)
   1.240 +  if (sort_map_array(ph) != true) {
   1.241      return false;
   1.242 +  }
   1.243  
   1.244    print_debug("first link map is at 0x%lx\n", first_link_map_addr);
   1.245  
   1.246 @@ -1380,8 +1408,9 @@
   1.247            add_lib_info_fd(ph, lib_name, lib_fd, lib_base);
   1.248            // Map info is added for the library (lib_name) so
   1.249            // we need to re-sort it before calling the p_pdread.
   1.250 -          if (sort_map_array(ph) != true)
   1.251 +          if (sort_map_array(ph) != true) {
   1.252              return false;
   1.253 +          }
   1.254          } else {
   1.255            print_debug("can't read ELF header for shared object %s\n", lib_name);
   1.256            close(lib_fd);
   1.257 @@ -1392,7 +1421,7 @@
   1.258  
   1.259      // read next link_map address
   1.260      if (ps_pread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET,
   1.261 -                 &link_map_addr, sizeof(uintptr_t)) != PS_OK) {
   1.262 +                  &link_map_addr, sizeof(uintptr_t)) != PS_OK) {
   1.263        print_debug("can't read next link in link_map\n");
   1.264        return false;
   1.265      }
   1.266 @@ -1408,7 +1437,7 @@
   1.267  
   1.268    struct ps_prochandle* ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle));
   1.269    if (ph == NULL) {
   1.270 -    print_debug("cant allocate ps_prochandle\n");
   1.271 +    print_debug("can't allocate ps_prochandle\n");
   1.272      return NULL;
   1.273    }
   1.274  
   1.275 @@ -1444,38 +1473,45 @@
   1.276    }
   1.277  
   1.278    if (read_elf_header(ph->core->exec_fd, &exec_ehdr) != true || exec_ehdr.e_type != ET_EXEC) {
   1.279 -     print_debug("executable file is not a valid ELF ET_EXEC file\n");
   1.280 -     goto err;
   1.281 +    print_debug("executable file is not a valid ELF ET_EXEC file\n");
   1.282 +    goto err;
   1.283    }
   1.284  
   1.285    // process core file segments
   1.286 -  if (read_core_segments(ph, &core_ehdr) != true)
   1.287 -     goto err;
   1.288 +  if (read_core_segments(ph, &core_ehdr) != true) {
   1.289 +    goto err;
   1.290 +  }
   1.291  
   1.292    // process exec file segments
   1.293 -  if (read_exec_segments(ph, &exec_ehdr) != true)
   1.294 -     goto err;
   1.295 +  if (read_exec_segments(ph, &exec_ehdr) != true) {
   1.296 +    goto err;
   1.297 +  }
   1.298  
   1.299    // exec file is also treated like a shared object for symbol search
   1.300    if (add_lib_info_fd(ph, exec_file, ph->core->exec_fd,
   1.301 -                      (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL)
   1.302 -     goto err;
   1.303 +                      (uintptr_t)0 + find_base_address(ph->core->exec_fd, &exec_ehdr)) == NULL) {
   1.304 +    goto err;
   1.305 +  }
   1.306  
   1.307    // allocate and sort maps into map_array, we need to do this
   1.308    // here because read_shared_lib_info needs to read from debuggee
   1.309    // address space
   1.310 -  if (sort_map_array(ph) != true)
   1.311 +  if (sort_map_array(ph) != true) {
   1.312      goto err;
   1.313 +  }
   1.314  
   1.315 -  if (read_shared_lib_info(ph) != true)
   1.316 +  if (read_shared_lib_info(ph) != true) {
   1.317      goto err;
   1.318 +  }
   1.319  
   1.320    // sort again because we have added more mappings from shared objects
   1.321 -  if (sort_map_array(ph) != true)
   1.322 +  if (sort_map_array(ph) != true) {
   1.323      goto err;
   1.324 +  }
   1.325  
   1.326 -  if (init_classsharing_workaround(ph) != true)
   1.327 +  if (init_classsharing_workaround(ph) != true) {
   1.328      goto err;
   1.329 +  }
   1.330  
   1.331    print_debug("Leave Pgrab_core\n");
   1.332    return ph;

mercurial