robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 1 | /* |
robert.swiecki@gmail.com | 3b630b4 | 2015-02-16 10:53:53 +0000 | [diff] [blame] | 2 | * |
robert.swiecki@gmail.com | 772b33d | 2015-02-14 20:35:00 +0000 | [diff] [blame] | 3 | * honggfuzz - architecture dependent code (LINUX/BFD) |
| 4 | * ----------------------------------------- |
robert.swiecki@gmail.com | 3b630b4 | 2015-02-16 10:53:53 +0000 | [diff] [blame] | 5 | * |
robert.swiecki@gmail.com | 772b33d | 2015-02-14 20:35:00 +0000 | [diff] [blame] | 6 | * Author: Robert Swiecki <swiecki@google.com> |
robert.swiecki@gmail.com | 3b630b4 | 2015-02-16 10:53:53 +0000 | [diff] [blame] | 7 | * |
robert.swiecki@gmail.com | 772b33d | 2015-02-14 20:35:00 +0000 | [diff] [blame] | 8 | * Copyright 2010-2015 by Google Inc. All Rights Reserved. |
robert.swiecki@gmail.com | 3b630b4 | 2015-02-16 10:53:53 +0000 | [diff] [blame] | 9 | * |
| 10 | * Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 11 | * not use this file except in compliance with the License. You may obtain |
robert.swiecki@gmail.com | 772b33d | 2015-02-14 20:35:00 +0000 | [diff] [blame] | 12 | * a copy of the License at |
robert.swiecki@gmail.com | 3b630b4 | 2015-02-16 10:53:53 +0000 | [diff] [blame] | 13 | * |
robert.swiecki@gmail.com | 772b33d | 2015-02-14 20:35:00 +0000 | [diff] [blame] | 14 | * http://www.apache.org/licenses/LICENSE-2.0 |
robert.swiecki@gmail.com | 3b630b4 | 2015-02-16 10:53:53 +0000 | [diff] [blame] | 15 | * |
robert.swiecki@gmail.com | 772b33d | 2015-02-14 20:35:00 +0000 | [diff] [blame] | 16 | * Unless required by applicable law or agreed to in writing, software |
| 17 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 18 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| 19 | * implied. See the License for the specific language governing |
| 20 | * permissions and limitations under the License. |
robert.swiecki@gmail.com | 3b630b4 | 2015-02-16 10:53:53 +0000 | [diff] [blame] | 21 | * |
robert.swiecki@gmail.com | 772b33d | 2015-02-14 20:35:00 +0000 | [diff] [blame] | 22 | */ |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 23 | |
| 24 | #include "common.h" |
| 25 | #include "linux/bfd.h" |
| 26 | |
| 27 | #include <bfd.h> |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 28 | #include <dis-asm.h> |
robert.swiecki@gmail.com | 45f8c40 | 2015-02-16 18:57:38 +0000 | [diff] [blame] | 29 | #include <pthread.h> |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 30 | #include <stdarg.h> |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 31 | #include <stddef.h> |
| 32 | #include <stdio.h> |
| 33 | #include <stdint.h> |
| 34 | #include <stdlib.h> |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 35 | #include <string.h> |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 36 | #include <inttypes.h> |
| 37 | #include <unistd.h> |
| 38 | |
| 39 | #include "files.h" |
| 40 | #include "log.h" |
| 41 | #include "util.h" |
| 42 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 43 | typedef struct { |
| 44 | bfd *bfdh; |
| 45 | asection *section; |
| 46 | asymbol **syms; |
| 47 | } bfd_t; |
| 48 | |
robert.swiecki@gmail.com | 45f8c40 | 2015-02-16 18:57:38 +0000 | [diff] [blame] | 49 | static pthread_mutex_t arch_bfd_mutex = PTHREAD_MUTEX_INITIALIZER; |
| 50 | |
robert.swiecki@gmail.com | b45bbc3 | 2015-02-16 15:11:50 +0000 | [diff] [blame] | 51 | static bool arch_bfdInit(pid_t pid, bfd_t * bfdParams) |
| 52 | { |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 53 | char fname[PATH_MAX]; |
| 54 | snprintf(fname, sizeof(fname), "/proc/%d/exe", pid); |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 55 | if ((bfdParams->bfdh = bfd_openr(fname, 0)) == NULL) { |
Robert Swiecki | c8c32db | 2015-10-09 18:06:22 +0200 | [diff] [blame] | 56 | LOG_E("bfd_openr(%s) failed", fname); |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 57 | return false; |
| 58 | } |
| 59 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 60 | if (!bfd_check_format(bfdParams->bfdh, bfd_object)) { |
Robert Swiecki | c8c32db | 2015-10-09 18:06:22 +0200 | [diff] [blame] | 61 | LOG_E("bfd_check_format() failed"); |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 62 | return false; |
| 63 | } |
| 64 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 65 | int storage_needed = bfd_get_symtab_upper_bound(bfdParams->bfdh); |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 66 | if (storage_needed <= 0) { |
Robert Swiecki | c8c32db | 2015-10-09 18:06:22 +0200 | [diff] [blame] | 67 | LOG_E("bfd_get_symtab_upper_bound() returned '%d'", storage_needed); |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 68 | return false; |
| 69 | } |
| 70 | |
Jagger | 090aead | 2016-04-05 23:49:40 +0200 | [diff] [blame] | 71 | bfdParams->syms = (asymbol **) util_Malloc(storage_needed); |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 72 | bfd_canonicalize_symtab(bfdParams->bfdh, bfdParams->syms); |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 73 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 74 | if ((bfdParams->section = bfd_get_section_by_name(bfdParams->bfdh, ".text")) == NULL) { |
Robert Swiecki | c8c32db | 2015-10-09 18:06:22 +0200 | [diff] [blame] | 75 | LOG_E("bfd_get_section_by_name('.text') failed"); |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 76 | return false; |
| 77 | } |
| 78 | |
| 79 | return true; |
| 80 | } |
| 81 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 82 | static void arch_bfdDestroy(bfd_t * bfdParams) |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 83 | { |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 84 | if (bfdParams->syms) { |
| 85 | free(bfdParams->syms); |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 86 | } |
robert.swiecki@gmail.com | e87be97 | 2015-02-16 13:44:43 +0000 | [diff] [blame] | 87 | if (bfdParams->bfdh) { |
Jagger | 090aead | 2016-04-05 23:49:40 +0200 | [diff] [blame] | 88 | bfd_close(bfdParams->bfdh); |
robert.swiecki@gmail.com | e87be97 | 2015-02-16 13:44:43 +0000 | [diff] [blame] | 89 | } |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 90 | } |
| 91 | |
| 92 | void arch_bfdResolveSyms(pid_t pid, funcs_t * funcs, size_t num) |
| 93 | { |
robert.swiecki@gmail.com | 45f8c40 | 2015-02-16 18:57:38 +0000 | [diff] [blame] | 94 | /* Guess what? libbfd is not multi-threading safe */ |
Robert Swiecki | 76ecd5e | 2016-03-16 14:57:03 +0100 | [diff] [blame] | 95 | MX_SCOPED_LOCK(&arch_bfd_mutex); |
robert.swiecki@gmail.com | 45f8c40 | 2015-02-16 18:57:38 +0000 | [diff] [blame] | 96 | |
robert.swiecki@gmail.com | 3605687 | 2015-02-16 19:06:45 +0000 | [diff] [blame] | 97 | bfd_init(); |
| 98 | |
Robert Swiecki | a9db9dd | 2016-03-09 16:29:37 +0100 | [diff] [blame] | 99 | __block bfd_t bfdParams = { |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 100 | .bfdh = NULL, |
| 101 | .section = NULL, |
| 102 | .syms = NULL, |
| 103 | }; |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 104 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 105 | if (arch_bfdInit(pid, &bfdParams) == false) { |
Robert Swiecki | a9db9dd | 2016-03-09 16:29:37 +0100 | [diff] [blame] | 106 | return; |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 107 | } |
Jagger | 4fe1869 | 2016-04-22 23:15:07 +0200 | [diff] [blame] | 108 | defer { |
| 109 | arch_bfdDestroy(&bfdParams); |
| 110 | }; |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 111 | |
| 112 | const char *func; |
| 113 | const char *file; |
| 114 | unsigned int line; |
| 115 | for (unsigned int i = 0; i < num; i++) { |
| 116 | snprintf(funcs[i].func, sizeof(funcs->func), "[UNKNOWN]"); |
| 117 | if (funcs[i].pc == NULL) { |
| 118 | continue; |
| 119 | } |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 120 | long offset = (long)funcs[i].pc - bfdParams.section->vma; |
| 121 | if ((offset < 0 || (unsigned long)offset > bfdParams.section->size)) { |
robert.swiecki@gmail.com | 5be8882 | 2015-02-14 13:12:09 +0000 | [diff] [blame] | 122 | continue; |
| 123 | } |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 124 | if (bfd_find_nearest_line |
robert.swiecki@gmail.com | 62e34ae | 2015-03-05 03:39:32 +0000 | [diff] [blame] | 125 | (bfdParams.bfdh, bfdParams.section, bfdParams.syms, offset, &file, &func, &line)) { |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 126 | snprintf(funcs[i].func, sizeof(funcs->func), "%s", func); |
robert.swiecki@gmail.com | 90e9911 | 2015-02-15 02:05:14 +0000 | [diff] [blame] | 127 | funcs[i].line = line; |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 128 | } |
| 129 | } |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 130 | } |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 131 | |
| 132 | static int arch_bfdFPrintF(void *buf, const char *fmt, ...) |
| 133 | { |
| 134 | va_list args; |
| 135 | va_start(args, fmt); |
| 136 | int ret = util_vssnprintf(buf, _HF_INSTR_SZ, fmt, args); |
| 137 | va_end(args); |
| 138 | |
| 139 | return ret; |
| 140 | } |
| 141 | |
| 142 | void arch_bfdDisasm(pid_t pid, uint8_t * mem, size_t size, char *instr) |
| 143 | { |
Robert Swiecki | 76ecd5e | 2016-03-16 14:57:03 +0100 | [diff] [blame] | 144 | MX_SCOPED_LOCK(&arch_bfd_mutex); |
robert.swiecki@gmail.com | 45f8c40 | 2015-02-16 18:57:38 +0000 | [diff] [blame] | 145 | |
robert.swiecki@gmail.com | 3605687 | 2015-02-16 19:06:45 +0000 | [diff] [blame] | 146 | bfd_init(); |
| 147 | |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 148 | char fname[PATH_MAX]; |
| 149 | snprintf(fname, sizeof(fname), "/proc/%d/exe", pid); |
| 150 | bfd *bfdh = bfd_openr(fname, NULL); |
| 151 | if (bfdh == NULL) { |
Robert Swiecki | c8c32db | 2015-10-09 18:06:22 +0200 | [diff] [blame] | 152 | LOG_W("bfd_openr('/proc/%d/exe') failed", pid); |
Robert Swiecki | a9db9dd | 2016-03-09 16:29:37 +0100 | [diff] [blame] | 153 | return; |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 154 | } |
Jagger | 4fe1869 | 2016-04-22 23:15:07 +0200 | [diff] [blame] | 155 | defer { |
| 156 | bfd_close(bfdh); |
| 157 | }; |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 158 | |
| 159 | if (!bfd_check_format(bfdh, bfd_object)) { |
Robert Swiecki | c8c32db | 2015-10-09 18:06:22 +0200 | [diff] [blame] | 160 | LOG_W("bfd_check_format() failed"); |
Robert Swiecki | a9db9dd | 2016-03-09 16:29:37 +0100 | [diff] [blame] | 161 | return; |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 162 | } |
| 163 | |
| 164 | disassembler_ftype disassemble = disassembler(bfdh); |
| 165 | if (disassemble == NULL) { |
Robert Swiecki | c8c32db | 2015-10-09 18:06:22 +0200 | [diff] [blame] | 166 | LOG_W("disassembler() failed"); |
Robert Swiecki | a9db9dd | 2016-03-09 16:29:37 +0100 | [diff] [blame] | 167 | return; |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 168 | } |
| 169 | |
| 170 | struct disassemble_info info; |
| 171 | init_disassemble_info(&info, instr, arch_bfdFPrintF); |
| 172 | info.arch = bfd_get_arch(bfdh); |
| 173 | info.mach = bfd_get_mach(bfdh); |
| 174 | info.buffer = mem; |
| 175 | info.buffer_length = size; |
| 176 | info.section = NULL; |
robert.swiecki@gmail.com | 45f8c40 | 2015-02-16 18:57:38 +0000 | [diff] [blame] | 177 | info.endian = bfd_little_endian(bfdh) ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG; |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 178 | disassemble_init_for_target(&info); |
| 179 | |
| 180 | strcpy(instr, ""); |
| 181 | if (disassemble(0, &info) <= 0) { |
robert.swiecki@gmail.com | 7271e8a | 2015-02-28 16:58:05 +0000 | [diff] [blame] | 182 | snprintf(instr, _HF_INSTR_SZ, "[DIS-ASM_FAILURE]"); |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 183 | } |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 184 | } |