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