blob: df5cd8a2d6428b054c5132407f19aa6f99bc87dc [file] [log] [blame]
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +00001/*
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00002 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +00003 * honggfuzz - architecture dependent code (LINUX/BFD)
4 * -----------------------------------------
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00005 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +00006 * Author: Robert Swiecki <swiecki@google.com>
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00007 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +00008 * Copyright 2010-2015 by Google Inc. All Rights Reserved.
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +00009 *
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.com772b33d2015-02-14 20:35:00 +000012 * a copy of the License at
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000013 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000014 * http://www.apache.org/licenses/LICENSE-2.0
robert.swiecki@gmail.com3b630b42015-02-16 10:53:53 +000015 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000016 * 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.com3b630b42015-02-16 10:53:53 +000021 *
robert.swiecki@gmail.com772b33d2015-02-14 20:35:00 +000022 */
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000023
24#include "common.h"
25#include "linux/bfd.h"
26
27#include <bfd.h>
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +000028#include <dis-asm.h>
robert.swiecki@gmail.com45f8c402015-02-16 18:57:38 +000029#include <pthread.h>
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +000030#include <stdarg.h>
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000031#include <stddef.h>
32#include <stdio.h>
33#include <stdint.h>
34#include <stdlib.h>
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +000035#include <string.h>
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000036#include <inttypes.h>
37#include <unistd.h>
38
39#include "files.h"
40#include "log.h"
41#include "util.h"
42
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +000043typedef struct {
44 bfd *bfdh;
45 asection *section;
46 asymbol **syms;
47} bfd_t;
48
robert.swiecki@gmail.com45f8c402015-02-16 18:57:38 +000049static pthread_mutex_t arch_bfd_mutex = PTHREAD_MUTEX_INITIALIZER;
50
robert.swiecki@gmail.comb45bbc32015-02-16 15:11:50 +000051static bool arch_bfdInit(pid_t pid, bfd_t * bfdParams)
52{
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000053 char fname[PATH_MAX];
54 snprintf(fname, sizeof(fname), "/proc/%d/exe", pid);
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +000055 if ((bfdParams->bfdh = bfd_openr(fname, 0)) == NULL) {
Robert Swieckic8c32db2015-10-09 18:06:22 +020056 LOG_E("bfd_openr(%s) failed", fname);
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000057 return false;
58 }
59
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +000060 if (!bfd_check_format(bfdParams->bfdh, bfd_object)) {
Robert Swieckic8c32db2015-10-09 18:06:22 +020061 LOG_E("bfd_check_format() failed");
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000062 return false;
63 }
64
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +000065 int storage_needed = bfd_get_symtab_upper_bound(bfdParams->bfdh);
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000066 if (storage_needed <= 0) {
Robert Swieckic8c32db2015-10-09 18:06:22 +020067 LOG_E("bfd_get_symtab_upper_bound() returned '%d'", storage_needed);
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000068 return false;
69 }
70
Jagger090aead2016-04-05 23:49:40 +020071 bfdParams->syms = (asymbol **) util_Malloc(storage_needed);
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +000072 bfd_canonicalize_symtab(bfdParams->bfdh, bfdParams->syms);
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000073
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +000074 if ((bfdParams->section = bfd_get_section_by_name(bfdParams->bfdh, ".text")) == NULL) {
Robert Swieckic8c32db2015-10-09 18:06:22 +020075 LOG_E("bfd_get_section_by_name('.text') failed");
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000076 return false;
77 }
78
79 return true;
80}
81
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +000082static void arch_bfdDestroy(bfd_t * bfdParams)
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000083{
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +000084 if (bfdParams->syms) {
85 free(bfdParams->syms);
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000086 }
robert.swiecki@gmail.come87be972015-02-16 13:44:43 +000087 if (bfdParams->bfdh) {
Jagger090aead2016-04-05 23:49:40 +020088 bfd_close(bfdParams->bfdh);
robert.swiecki@gmail.come87be972015-02-16 13:44:43 +000089 }
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000090}
91
92void arch_bfdResolveSyms(pid_t pid, funcs_t * funcs, size_t num)
93{
robert.swiecki@gmail.com45f8c402015-02-16 18:57:38 +000094 /* Guess what? libbfd is not multi-threading safe */
Robert Swiecki76ecd5e2016-03-16 14:57:03 +010095 MX_SCOPED_LOCK(&arch_bfd_mutex);
robert.swiecki@gmail.com45f8c402015-02-16 18:57:38 +000096
robert.swiecki@gmail.com36056872015-02-16 19:06:45 +000097 bfd_init();
98
Robert Swieckia9db9dd2016-03-09 16:29:37 +010099 __block bfd_t bfdParams = {
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000100 .bfdh = NULL,
101 .section = NULL,
102 .syms = NULL,
103 };
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000104
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000105 if (arch_bfdInit(pid, &bfdParams) == false) {
Robert Swieckia9db9dd2016-03-09 16:29:37 +0100106 return;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000107 }
Jagger4fe18692016-04-22 23:15:07 +0200108 defer {
109 arch_bfdDestroy(&bfdParams);
110 };
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000111
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.com576232b2015-02-14 19:44:32 +0000120 long offset = (long)funcs[i].pc - bfdParams.section->vma;
121 if ((offset < 0 || (unsigned long)offset > bfdParams.section->size)) {
robert.swiecki@gmail.com5be88822015-02-14 13:12:09 +0000122 continue;
123 }
robert.swiecki@gmail.com576232b2015-02-14 19:44:32 +0000124 if (bfd_find_nearest_line
robert.swiecki@gmail.com62e34ae2015-03-05 03:39:32 +0000125 (bfdParams.bfdh, bfdParams.section, bfdParams.syms, offset, &file, &func, &line)) {
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000126 snprintf(funcs[i].func, sizeof(funcs->func), "%s", func);
robert.swiecki@gmail.com90e99112015-02-15 02:05:14 +0000127 funcs[i].line = line;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000128 }
129 }
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000130}
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000131
132static 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
142void arch_bfdDisasm(pid_t pid, uint8_t * mem, size_t size, char *instr)
143{
Robert Swiecki76ecd5e2016-03-16 14:57:03 +0100144 MX_SCOPED_LOCK(&arch_bfd_mutex);
robert.swiecki@gmail.com45f8c402015-02-16 18:57:38 +0000145
robert.swiecki@gmail.com36056872015-02-16 19:06:45 +0000146 bfd_init();
147
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000148 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 Swieckic8c32db2015-10-09 18:06:22 +0200152 LOG_W("bfd_openr('/proc/%d/exe') failed", pid);
Robert Swieckia9db9dd2016-03-09 16:29:37 +0100153 return;
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000154 }
Jagger4fe18692016-04-22 23:15:07 +0200155 defer {
156 bfd_close(bfdh);
157 };
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000158
159 if (!bfd_check_format(bfdh, bfd_object)) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200160 LOG_W("bfd_check_format() failed");
Robert Swieckia9db9dd2016-03-09 16:29:37 +0100161 return;
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000162 }
163
164 disassembler_ftype disassemble = disassembler(bfdh);
165 if (disassemble == NULL) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200166 LOG_W("disassembler() failed");
Robert Swieckia9db9dd2016-03-09 16:29:37 +0100167 return;
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000168 }
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.com45f8c402015-02-16 18:57:38 +0000177 info.endian = bfd_little_endian(bfdh) ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000178 disassemble_init_for_target(&info);
179
180 strcpy(instr, "");
181 if (disassemble(0, &info) <= 0) {
robert.swiecki@gmail.com7271e8a2015-02-28 16:58:05 +0000182 snprintf(instr, _HF_INSTR_SZ, "[DIS-ASM_FAILURE]");
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000183 }
robert.swiecki@gmail.com9e2d43d2015-02-16 12:17:39 +0000184}