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 18namespace inspector { 19 20int verbosity_level = 0; 21 22extern "C" 23void 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 30const 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 37void 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 48void 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 58void 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 63zx_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 77zx_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 101typedef Elf32_Half elf_half_t; 102typedef Elf32_Off elf_off_t; 103// ELF used "word" for 32 bits, sigh. 104typedef Elf32_Word elf_word_t; 105typedef Elf32_Word elf_native_word_t; 106typedef 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 117typedef Elf64_Half elf_half_t; 118typedef Elf64_Off elf_off_t; 119typedef Elf64_Word elf_word_t; 120typedef Elf64_Xword elf_native_word_t; 121typedef Elf64_Phdr elf_phdr_t; 122 123#endif 124 125zx_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