1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <elf.h>
6 #include <limits.h>
7 #include <stdarg.h>
8 #include <stdio.h>
9 #include <string.h>
10
11 #include <zircon/syscalls.h>
12 #include <zircon/syscalls/object.h>
13 #include <zircon/status.h>
14
15 #include "inspector/inspector.h"
16 #include "utils-impl.h"
17
18 namespace inspector {
19
20 int verbosity_level = 0;
21
22 extern "C"
inspector_set_verbosity(int level)23 void inspector_set_verbosity(int level) {
24 verbosity_level = level;
25 }
26
27 // Same as basename, except will not modify |path|.
28 // Returns "" if |path| has a trailing /.
29
path_basename(const char * path)30 const char* path_basename(const char* path) {
31 const char* base = strrchr(path, '/');
32 if (base == nullptr)
33 return path;
34 return base + 1;
35 }
36
do_print_debug(const char * file,int line,const char * func,const char * fmt,...)37 void do_print_debug(const char* file, int line, const char* func, const char* fmt, ...) {
38 fflush(stdout);
39 const char* base = path_basename(file);
40 va_list args;
41 va_start(args, fmt);
42 fprintf(stderr, "%s:%d: %s: ", base, line, func);
43 vfprintf(stderr, fmt, args);
44 va_end(args);
45 fflush(stderr); // TODO: output is getting lost
46 }
47
do_print_error(const char * file,int line,const char * fmt,...)48 void do_print_error(const char* file, int line, const char* fmt, ...) {
49 const char* base = path_basename(file);
50 va_list args;
51 va_start(args, fmt);
52 fprintf(stderr, "inspector: %s:%d: ", base, line);
53 vfprintf(stderr, fmt, args);
54 fprintf(stderr, "\n");
55 va_end(args);
56 }
57
do_print_zx_error(const char * file,int line,const char * what,zx_status_t status)58 void do_print_zx_error(const char* file, int line, const char* what, zx_status_t status) {
59 do_print_error(file, line, "%s: %d (%s)",
60 what, status, zx_status_get_string(status));
61 }
62
read_mem(zx_handle_t h,zx_vaddr_t vaddr,void * ptr,size_t len)63 zx_status_t read_mem(zx_handle_t h, zx_vaddr_t vaddr, void* ptr, size_t len) {
64 size_t actual;
65 zx_status_t status = zx_process_read_memory(h, vaddr, ptr, len, &actual);
66 if (status < 0) {
67 printf("read_mem @%p FAILED %zd\n", (void*) vaddr, len);
68 return status;
69 }
70 if (len != actual) {
71 printf("read_mem @%p FAILED, short read %zd\n", (void*) vaddr, len);
72 return ZX_ERR_IO;
73 }
74 return ZX_OK;
75 }
76
fetch_string(zx_handle_t h,zx_vaddr_t vaddr,char * ptr,size_t max)77 zx_status_t fetch_string(zx_handle_t h, zx_vaddr_t vaddr, char* ptr, size_t max) {
78 while (max > 1) {
79 zx_status_t status;
80 if ((status = read_mem(h, vaddr, ptr, 1)) < 0) {
81 *ptr = 0;
82 return status;
83 }
84 ptr++;
85 vaddr++;
86 max--;
87 }
88 *ptr = 0;
89 return ZX_OK;
90 }
91
92 #if UINT_MAX == ULONG_MAX
93
94 #define ehdr_off_phoff offsetof(Elf32_Ehdr, e_phoff)
95 #define ehdr_off_phnum offsetof(Elf32_Ehdr, e_phnum)
96
97 #define phdr_off_type offsetof(Elf32_Phdr, p_type)
98 #define phdr_off_offset offsetof(Elf32_Phdr, p_offset)
99 #define phdr_off_filesz offsetof(Elf32_Phdr, p_filesz)
100
101 typedef Elf32_Half elf_half_t;
102 typedef Elf32_Off elf_off_t;
103 // ELF used "word" for 32 bits, sigh.
104 typedef Elf32_Word elf_word_t;
105 typedef Elf32_Word elf_native_word_t;
106 typedef Elf32_Phdr elf_phdr_t;
107
108 #else
109
110 #define ehdr_off_phoff offsetof(Elf64_Ehdr, e_phoff)
111 #define ehdr_off_phnum offsetof(Elf64_Ehdr, e_phnum)
112
113 #define phdr_off_type offsetof(Elf64_Phdr, p_type)
114 #define phdr_off_offset offsetof(Elf64_Phdr, p_offset)
115 #define phdr_off_filesz offsetof(Elf64_Phdr, p_filesz)
116
117 typedef Elf64_Half elf_half_t;
118 typedef Elf64_Off elf_off_t;
119 typedef Elf64_Word elf_word_t;
120 typedef Elf64_Xword elf_native_word_t;
121 typedef Elf64_Phdr elf_phdr_t;
122
123 #endif
124
fetch_build_id(zx_handle_t h,zx_vaddr_t base,char * buf,size_t buf_size)125 zx_status_t fetch_build_id(zx_handle_t h, zx_vaddr_t base, char* buf, size_t buf_size) {
126 zx_vaddr_t vaddr = base;
127 uint8_t tmp[4];
128 zx_status_t status;
129
130 if (buf_size < MAX_BUILDID_SIZE * 2 + 1)
131 return ZX_ERR_INVALID_ARGS;
132
133 status = read_mem(h, vaddr, tmp, 4);
134 if (status != ZX_OK)
135 return status;
136 if (memcmp(tmp, ELFMAG, SELFMAG))
137 return ZX_ERR_WRONG_TYPE;
138
139 elf_off_t phoff;
140 elf_half_t num;
141 status = read_mem(h, vaddr + ehdr_off_phoff, &phoff, sizeof(phoff));
142 if (status != ZX_OK)
143 return status;
144 status = read_mem(h, vaddr + ehdr_off_phnum, &num, sizeof(num));
145 if (status != ZX_OK)
146 return status;
147
148 for (unsigned n = 0; n < num; n++) {
149 zx_vaddr_t phaddr = vaddr + phoff + (n * sizeof(elf_phdr_t));
150 elf_word_t type;
151 status = read_mem(h, phaddr + phdr_off_type, &type, sizeof(type));
152 if (status != ZX_OK)
153 return status;
154 if (type != PT_NOTE)
155 continue;
156
157 elf_off_t off;
158 elf_native_word_t size;
159 status = read_mem(h, phaddr + phdr_off_offset, &off, sizeof(off));
160 if (status != ZX_OK)
161 return status;
162 status = read_mem(h, phaddr + phdr_off_filesz, &size, sizeof(size));
163 if (status != ZX_OK)
164 return status;
165
166 struct {
167 Elf32_Nhdr hdr;
168 char name[sizeof("GNU")];
169 } hdr;
170 while (size > sizeof(hdr)) {
171 status = read_mem(h, vaddr + off, &hdr, sizeof(hdr));
172 if (status != ZX_OK)
173 return status;
174 size_t header_size =
175 sizeof(Elf32_Nhdr) + ((hdr.hdr.n_namesz + 3) & -4);
176 size_t payload_size = (hdr.hdr.n_descsz + 3) & -4;
177 off += header_size;
178 size -= header_size;
179 zx_vaddr_t payload_vaddr = vaddr + off;
180 off += payload_size;
181 size -= payload_size;
182 if (hdr.hdr.n_type != NT_GNU_BUILD_ID ||
183 hdr.hdr.n_namesz != sizeof("GNU") ||
184 memcmp(hdr.name, "GNU", sizeof("GNU")) != 0) {
185 continue;
186 }
187 if (hdr.hdr.n_descsz > MAX_BUILDID_SIZE) {
188 snprintf(buf, buf_size,
189 "build_id_too_large_%u", hdr.hdr.n_descsz);
190 } else {
191 uint8_t buildid[MAX_BUILDID_SIZE];
192 status = read_mem(h, payload_vaddr, buildid, hdr.hdr.n_descsz);
193 if (status != ZX_OK)
194 return status;
195 for (uint32_t i = 0; i < hdr.hdr.n_descsz; ++i) {
196 snprintf(&buf[i * 2], 3, "%02x", buildid[i]);
197 }
198 }
199 return ZX_OK;
200 }
201 }
202
203 return ZX_ERR_NOT_FOUND;
204 }
205
206 } // namespace inspector
207