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> |
| 29 | #include <stdarg.h> |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 30 | #include <stddef.h> |
| 31 | #include <stdio.h> |
| 32 | #include <stdint.h> |
| 33 | #include <stdlib.h> |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 34 | #include <string.h> |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 35 | #include <inttypes.h> |
| 36 | #include <unistd.h> |
| 37 | |
| 38 | #include "files.h" |
| 39 | #include "log.h" |
| 40 | #include "util.h" |
| 41 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 42 | typedef struct { |
| 43 | bfd *bfdh; |
| 44 | asection *section; |
| 45 | asymbol **syms; |
| 46 | } bfd_t; |
| 47 | |
robert.swiecki@gmail.com | b45bbc3 | 2015-02-16 15:11:50 +0000 | [diff] [blame^] | 48 | void arch_bfdPrepare(void) |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 49 | { |
| 50 | bfd_init(); |
robert.swiecki@gmail.com | b45bbc3 | 2015-02-16 15:11:50 +0000 | [diff] [blame^] | 51 | } |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 52 | |
robert.swiecki@gmail.com | b45bbc3 | 2015-02-16 15:11:50 +0000 | [diff] [blame^] | 53 | static bool arch_bfdInit(pid_t pid, bfd_t * bfdParams) |
| 54 | { |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 55 | char fname[PATH_MAX]; |
| 56 | snprintf(fname, sizeof(fname), "/proc/%d/exe", pid); |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 57 | if ((bfdParams->bfdh = bfd_openr(fname, 0)) == NULL) { |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 58 | LOGMSG(l_ERROR, "bfd_openr(%s) failed", fname); |
| 59 | return false; |
| 60 | } |
| 61 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 62 | if (!bfd_check_format(bfdParams->bfdh, bfd_object)) { |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 63 | LOGMSG(l_ERROR, "bfd_check_format() failed"); |
| 64 | return false; |
| 65 | } |
| 66 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 67 | int storage_needed = bfd_get_symtab_upper_bound(bfdParams->bfdh); |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 68 | if (storage_needed <= 0) { |
| 69 | LOGMSG(l_ERROR, "bfd_get_symtab_upper_bound() returned '%d'", storage_needed); |
| 70 | return false; |
| 71 | } |
| 72 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 73 | if ((bfdParams->syms = (asymbol **) malloc(storage_needed)) == NULL) { |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 74 | LOGMSG_P(l_ERROR, "malloc(%d) failed", storage_needed); |
| 75 | return false; |
| 76 | } |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 77 | bfd_canonicalize_symtab(bfdParams->bfdh, bfdParams->syms); |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 78 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 79 | if ((bfdParams->section = bfd_get_section_by_name(bfdParams->bfdh, ".text")) == NULL) { |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 80 | LOGMSG(l_ERROR, "bfd_get_section_by_name('.text') failed"); |
| 81 | return false; |
| 82 | } |
| 83 | |
| 84 | return true; |
| 85 | } |
| 86 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 87 | static void arch_bfdDestroy(bfd_t * bfdParams) |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 88 | { |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 89 | if (bfdParams->syms) { |
| 90 | free(bfdParams->syms); |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 91 | } |
robert.swiecki@gmail.com | e87be97 | 2015-02-16 13:44:43 +0000 | [diff] [blame] | 92 | if (bfdParams->bfdh) { |
| 93 | bfd_close(bfdParams->bfdh); |
| 94 | } |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 95 | return; |
| 96 | } |
| 97 | |
| 98 | void arch_bfdResolveSyms(pid_t pid, funcs_t * funcs, size_t num) |
| 99 | { |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 100 | bfd_t bfdParams = { |
| 101 | .bfdh = NULL, |
| 102 | .section = NULL, |
| 103 | .syms = NULL, |
| 104 | }; |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 105 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 106 | if (arch_bfdInit(pid, &bfdParams) == false) { |
| 107 | arch_bfdDestroy(&bfdParams); |
| 108 | return; |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | const char *func; |
| 112 | const char *file; |
| 113 | unsigned int line; |
| 114 | for (unsigned int i = 0; i < num; i++) { |
| 115 | snprintf(funcs[i].func, sizeof(funcs->func), "[UNKNOWN]"); |
| 116 | if (funcs[i].pc == NULL) { |
| 117 | continue; |
| 118 | } |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 119 | long offset = (long)funcs[i].pc - bfdParams.section->vma; |
| 120 | if ((offset < 0 || (unsigned long)offset > bfdParams.section->size)) { |
robert.swiecki@gmail.com | 5be8882 | 2015-02-14 13:12:09 +0000 | [diff] [blame] | 121 | continue; |
| 122 | } |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 123 | if (bfd_find_nearest_line |
| 124 | (bfdParams.bfdh, bfdParams.section, bfdParams.syms, offset, &file, &func, &line)) { |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 125 | snprintf(funcs[i].func, sizeof(funcs->func), "%s", func); |
robert.swiecki@gmail.com | 90e9911 | 2015-02-15 02:05:14 +0000 | [diff] [blame] | 126 | funcs[i].line = line; |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 127 | } |
| 128 | } |
| 129 | |
robert.swiecki@gmail.com | 576232b | 2015-02-14 19:44:32 +0000 | [diff] [blame] | 130 | arch_bfdDestroy(&bfdParams); |
| 131 | return; |
robert.swiecki@gmail.com | a0d8714 | 2015-02-14 13:11:18 +0000 | [diff] [blame] | 132 | } |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 133 | |
| 134 | static int arch_bfdFPrintF(void *buf, const char *fmt, ...) |
| 135 | { |
| 136 | va_list args; |
| 137 | va_start(args, fmt); |
| 138 | int ret = util_vssnprintf(buf, _HF_INSTR_SZ, fmt, args); |
| 139 | va_end(args); |
| 140 | |
| 141 | return ret; |
| 142 | } |
| 143 | |
| 144 | void arch_bfdDisasm(pid_t pid, uint8_t * mem, size_t size, char *instr) |
| 145 | { |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 146 | char fname[PATH_MAX]; |
| 147 | snprintf(fname, sizeof(fname), "/proc/%d/exe", pid); |
| 148 | bfd *bfdh = bfd_openr(fname, NULL); |
| 149 | if (bfdh == NULL) { |
| 150 | LOGMSG(l_WARN, "bfd_openr('/proc/%d/exe') failed", pid); |
robert.swiecki@gmail.com | d712370 | 2015-02-16 14:50:50 +0000 | [diff] [blame] | 151 | goto out; |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 152 | } |
| 153 | |
| 154 | if (!bfd_check_format(bfdh, bfd_object)) { |
| 155 | LOGMSG(l_WARN, "bfd_check_format() failed"); |
robert.swiecki@gmail.com | d712370 | 2015-02-16 14:50:50 +0000 | [diff] [blame] | 156 | goto out; |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 157 | } |
| 158 | |
| 159 | disassembler_ftype disassemble = disassembler(bfdh); |
| 160 | if (disassemble == NULL) { |
| 161 | LOGMSG(l_WARN, "disassembler() failed"); |
robert.swiecki@gmail.com | d712370 | 2015-02-16 14:50:50 +0000 | [diff] [blame] | 162 | goto out; |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | struct disassemble_info info; |
| 166 | init_disassemble_info(&info, instr, arch_bfdFPrintF); |
| 167 | info.arch = bfd_get_arch(bfdh); |
| 168 | info.mach = bfd_get_mach(bfdh); |
| 169 | info.buffer = mem; |
| 170 | info.buffer_length = size; |
| 171 | info.section = NULL; |
| 172 | disassemble_init_for_target(&info); |
| 173 | |
| 174 | strcpy(instr, ""); |
| 175 | if (disassemble(0, &info) <= 0) { |
| 176 | snprintf(instr, _HF_INSTR_SZ, "[UNKNOWN]"); |
| 177 | } |
robert.swiecki@gmail.com | d712370 | 2015-02-16 14:50:50 +0000 | [diff] [blame] | 178 | |
| 179 | out: |
| 180 | bfdh ? bfd_close(bfdh) : 0; |
robert.swiecki@gmail.com | 9e2d43d | 2015-02-16 12:17:39 +0000 | [diff] [blame] | 181 | return; |
| 182 | } |