1824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm/* libunwind - a platform-independent unwind library 25724bee8c27219ac277ea76d75dc70fa830eaac0hp.com!davidm Copyright (C) 2003, 2005 Hewlett-Packard Co 3e6b9f350f78ecd9ef3b8a3e721f9435c94fc2562David Mosberger-Tang Copyright (C) 2007 David Mosberger-Tang 4e6b9f350f78ecd9ef3b8a3e721f9435c94fc2562David Mosberger-Tang Contributed by David Mosberger-Tang <dmosberger@gmail.com> 5824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm 6824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmThis file is part of libunwind. 7824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm 8824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmPermission is hereby granted, free of charge, to any person obtaining 9824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidma copy of this software and associated documentation files (the 10824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm"Software"), to deal in the Software without restriction, including 11824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmwithout limitation the rights to use, copy, modify, merge, publish, 12824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmdistribute, sublicense, and/or sell copies of the Software, and to 13824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmpermit persons to whom the Software is furnished to do so, subject to 14824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmthe following conditions: 15824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm 16824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmThe above copyright notice and this permission notice shall be 17824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmincluded in all copies or substantial portions of the Software. 18824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm 19824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidmWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 26824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm 27824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm#include <fcntl.h> 28cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris#include <stddef.h> 29824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm#include <unistd.h> 30824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm 31824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm#include <sys/mman.h> 3263d7003ef7c8f791d52cd88add0cee0d72cb6a5fmostang.com!davidm#include <sys/stat.h> 33824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm 34d41a453bbf195818e3fa66ed0a123f0c06aa754bArun Sharma#include "libunwind_i.h" 35f4a8df5f4f338f1a12c25213227e98b34b42447fChristopher Ferris#include "map_info.h" 36d41a453bbf195818e3fa66ed0a123f0c06aa754bArun Sharma 37824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm#if ELF_CLASS == ELFCLASS32 384fafd8cbf7464f50b30e2983e332ddebef8b5acchp.com!davidm# define ELF_W(x) ELF32_##x 394fafd8cbf7464f50b30e2983e332ddebef8b5acchp.com!davidm# define Elf_W(x) Elf32_##x 404fafd8cbf7464f50b30e2983e332ddebef8b5acchp.com!davidm# define elf_w(x) _Uelf32_##x 41824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm#else 424fafd8cbf7464f50b30e2983e332ddebef8b5acchp.com!davidm# define ELF_W(x) ELF64_##x 434fafd8cbf7464f50b30e2983e332ddebef8b5acchp.com!davidm# define Elf_W(x) Elf64_##x 444fafd8cbf7464f50b30e2983e332ddebef8b5acchp.com!davidm# define elf_w(x) _Uelf64_##x 45824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm#endif 46824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm 47cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris#define GET_FIELD(ei, offset, struct_name, elf_struct, field, check_cached) \ 48cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris { \ 49cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (!check_cached || (elf_struct)->field == 0) { \ 50cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (sizeof((elf_struct)->field) != elf_w (memory_read) ( \ 51cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris ei, ei->u.memory.map->start + offset + offsetof(struct_name, field), \ 52cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris (uint8_t*) &((elf_struct)->field), sizeof((elf_struct)->field), false)) { \ 53cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris return false; \ 54cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris } \ 55cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris } \ 56cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris } 57cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 58cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris#define GET_EHDR_FIELD(ei, ehdr, field, check_cached) \ 59cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris GET_FIELD(ei, 0, Elf_W(Ehdr), ehdr, field, check_cached) 60cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 61cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris#define GET_PHDR_FIELD(ei, offset, phdr, field) \ 62cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris GET_FIELD(ei, offset, Elf_W(Phdr), phdr, field, false) 63cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 64cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris#define GET_SHDR_FIELD(ei, offset, shdr, field) \ 65cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris GET_FIELD(ei, offset, Elf_W(Shdr), shdr, field, false) 66cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 67cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris#define GET_SYM_FIELD(ei, offset, sym, field) \ 68cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris GET_FIELD(ei, offset, Elf_W(Sym), sym, field, false) 69cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 70cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris#define GET_DYN_FIELD(ei, offset, dyn, field) \ 71cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris GET_FIELD(ei, offset, Elf_W(Dyn), dyn, field, false) 72cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 73cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferrisextern bool elf_w (get_proc_name) ( 74cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris unw_addr_space_t as, pid_t pid, unw_word_t ip, char* buf, size_t len, 75cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris unw_word_t* offp, void* as_arg); 76cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 77cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferrisextern bool elf_w (get_proc_name_in_image) ( 78cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris unw_addr_space_t as, struct elf_image* ei, unsigned long segbase, 79cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris unsigned long mapoff, unw_word_t ip, char* buf, size_t buf_len, unw_word_t* offp); 80cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 81cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferrisextern bool elf_w (get_load_base) (struct elf_image* ei, unw_word_t mapoff, unw_word_t* load_base); 82cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 83cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferrisextern size_t elf_w (memory_read) ( 84cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris struct elf_image* ei, unw_word_t addr, uint8_t* buffer, size_t bytes, bool string_read); 85cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 86cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferrisstatic inline bool elf_w (valid_object_mapped) (struct elf_image* ei) { 87cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (ei->u.mapped.size <= EI_VERSION) { 88cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris return false; 89cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris } 90cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 91cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris uint8_t* e_ident = (uint8_t*) ei->u.mapped.image; 92cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris return (memcmp (ei->u.mapped.image, ELFMAG, SELFMAG) == 0 93cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris && e_ident[EI_CLASS] == ELF_CLASS && e_ident[EI_VERSION] != EV_NONE 94cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris && e_ident[EI_VERSION] <= EV_CURRENT); 953d08506936d16401aade168de0c95646b3f54a94Arun Sharma} 963d08506936d16401aade168de0c95646b3f54a94Arun Sharma 97cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferrisstatic inline bool elf_w (valid_object_memory) (struct elf_image* ei) { 98cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris uint8_t e_ident[EI_NIDENT]; 99cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris struct map_info* map = ei->u.memory.map; 100cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (SELFMAG != elf_w (memory_read) (ei, map->start, e_ident, SELFMAG, false)) { 101cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris return false; 102cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris } 103cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (memcmp (e_ident, ELFMAG, SELFMAG) != 0) { 104cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris return false; 105cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris } 106cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris // Read the rest of the ident data. 107cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (EI_NIDENT - SELFMAG != elf_w (memory_read) ( 108cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris ei, map->start + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG, false)) { 109cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris return false; 110cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris } 111cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris return e_ident[EI_CLASS] == ELF_CLASS && e_ident[EI_VERSION] != EV_NONE 112cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris && e_ident[EI_VERSION] <= EV_CURRENT; 113cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris} 114cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 115cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferrisstatic inline bool elf_map_image (struct elf_image* ei, const char* path) { 116824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm struct stat stat; 117824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm int fd; 118824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm 119824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm fd = open (path, O_RDONLY); 120cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (fd < 0) { 121cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris return false; 122cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris } 123824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm 124cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (fstat (fd, &stat) == -1) { 125cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris close (fd); 126cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris return false; 127cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris } 128824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm 129cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris ei->u.mapped.size = stat.st_size; 130cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris ei->u.mapped.image = mmap (NULL, ei->u.mapped.size, PROT_READ, MAP_PRIVATE, fd, 0); 131824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm close (fd); 132cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (ei->u.mapped.image == MAP_FAILED) { 133cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris return false; 134cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris } 135824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm 136cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris ei->valid = elf_w (valid_object_mapped) (ei); 137cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (!ei->valid) { 138cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris munmap (ei->u.mapped.image, ei->u.mapped.size); 1397124451dfc655b24e549ded8594c449393ab7597Christopher Ferris return false; 140a83e96cc1cc48c6c229d9462ab13ef6479a84143Arun Sharma } 141a83e96cc1cc48c6c229d9462ab13ef6479a84143Arun Sharma 142cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris ei->mapped = true; 143cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris // Set to true for cases where this is called outside of elf_map_cached. 144cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris ei->load_attempted = true; 145cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 146cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris return true; 147824d6619b500a86ff2fc680268357f0215d59b0cmostang.com!davidm} 148f4a8df5f4f338f1a12c25213227e98b34b42447fChristopher Ferris 149cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferrisstatic inline bool elf_map_cached_image ( 150cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris unw_addr_space_t as, void* as_arg, struct map_info* map, unw_word_t ip) { 151f4a8df5f4f338f1a12c25213227e98b34b42447fChristopher Ferris intrmask_t saved_mask; 152f4a8df5f4f338f1a12c25213227e98b34b42447fChristopher Ferris 153cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris // Lock while loading the cached elf image. 154f4a8df5f4f338f1a12c25213227e98b34b42447fChristopher Ferris lock_acquire (&map->ei_lock, saved_mask); 155cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (!map->ei.load_attempted) { 156cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris map->ei.load_attempted = true; 157cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris 158cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (!elf_map_image (&map->ei, map->path)) { 159cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris // If the image cannot be loaded, we'll read data directly from 160cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris // the process using the access_mem function. 161cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (map->flags & PROT_READ) { 162cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris map->ei.u.memory.map = map; 163cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris map->ei.u.memory.as = as; 164cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris map->ei.u.memory.as_arg = as_arg; 165cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris map->ei.valid = elf_w (valid_object_memory) (&map->ei); 166cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris } 167cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris } 168cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris unw_word_t load_base; 169cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris if (map->ei.valid && elf_w (get_load_base) (&map->ei, map->offset, &load_base)) { 170cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris map->load_base = load_base; 171f4a8df5f4f338f1a12c25213227e98b34b42447fChristopher Ferris } 172cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris } 173f4a8df5f4f338f1a12c25213227e98b34b42447fChristopher Ferris lock_release (&map->ei_lock, saved_mask); 174cdf0d03deb539dd92d5752d237127b74406c631fChristopher Ferris return map->ei.valid; 175f4a8df5f4f338f1a12c25213227e98b34b42447fChristopher Ferris} 176