blob: d106763a39c7134f2bc39f290c039e612e2a94c7 [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/UNWIND)
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 Swiecki46288f72018-02-27 17:28:47 +01008 * Copyright 2010-2018 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
Robert Swiecki38ce20c2018-08-21 21:20:48 +020024#include "linux/unwind.h"
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000025
Robert Swieckid0fa62c2017-09-28 18:11:05 +020026#include <endian.h>
27#include <libunwind-ptrace.h>
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +020028#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000031
Robert Swieckifafed7d2017-11-16 23:15:10 +010032#include "honggfuzz.h"
Robert Swiecki246af3e2018-01-05 14:56:32 +010033#include "libhfcommon/common.h"
34#include "libhfcommon/log.h"
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000035
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +030036/*
37 * WARNING: Ensure that _UPT-info structs are not shared between threads
38 * http://www.nongnu.org/libunwind/man/libunwind-ptrace(3).html
39 */
40
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +030041// libunwind error codes used for debugging
Robert Swiecki4e595fb2017-10-11 17:26:51 +020042static const char* UNW_ER[] = {
Robert Swieckid50ed422017-11-13 23:32:26 +010043 "UNW_ESUCCESS", /* no error */
44 "UNW_EUNSPEC", /* unspecified (general) error */
45 "UNW_ENOMEM", /* out of memory */
46 "UNW_EBADREG", /* bad register number */
Robert Swiecki4e595fb2017-10-11 17:26:51 +020047 "UNW_EREADONLYREG", /* attempt to write read-only register */
Robert Swieckid50ed422017-11-13 23:32:26 +010048 "UNW_ESTOPUNWIND", /* stop unwinding */
49 "UNW_EINVALIDIP", /* invalid IP */
50 "UNW_EBADFRAME", /* bad frame */
51 "UNW_EINVAL", /* unsupported operation or bad value */
52 "UNW_EBADVERSION", /* unwind info has unsupported version */
53 "UNW_ENOINFO" /* no unwind info found */
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +030054};
55
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +020056typedef struct {
57 unsigned long start;
58 unsigned long end;
Robert Swieckibbb476e2020-04-29 15:57:06 +020059 char perms[6];
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +020060 unsigned long offset;
Robert Swieckibbb476e2020-04-29 15:57:06 +020061 char dev[8];
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +020062 unsigned long inode;
Robert Swieckibbb476e2020-04-29 15:57:06 +020063 char name[PATH_MAX];
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +020064} procMap_t;
65
Robert Swieckid50ed422017-11-13 23:32:26 +010066static procMap_t* arch_parsePidMaps(pid_t pid, size_t* mapsCount) {
Robert Swieckibbb476e2020-04-29 15:57:06 +020067 FILE* f = NULL;
68 char fProcMaps[PATH_MAX] = {0};
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +020069 snprintf(fProcMaps, PATH_MAX, "/proc/%d/maps", pid);
70
71 if ((f = fopen(fProcMaps, "rb")) == NULL) {
72 PLOG_E("Couldn't open '%s' - R/O mode", fProcMaps);
73 return 0;
74 }
Robert Swiecki3ab16642018-01-12 18:08:37 +010075 defer {
76 fclose(f);
77 };
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +020078
Robert Swieckibbb476e2020-04-29 15:57:06 +020079 *mapsCount = 0;
Robert Swiecki4e595fb2017-10-11 17:26:51 +020080 procMap_t* mapsList = malloc(sizeof(procMap_t));
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +020081 if (mapsList == NULL) {
82 PLOG_W("malloc(size='%zu')", sizeof(procMap_t));
83 return NULL;
84 }
85
86 while (!feof(f)) {
87 char buf[sizeof(procMap_t) + 1];
88 if (fgets(buf, sizeof(buf), f) == 0) {
89 break;
90 }
91
92 mapsList[*mapsCount].name[0] = '\0';
93 sscanf(buf, "%lx-%lx %5s %lx %7s %ld %s", &mapsList[*mapsCount].start,
Robert Swiecki4e595fb2017-10-11 17:26:51 +020094 &mapsList[*mapsCount].end, mapsList[*mapsCount].perms, &mapsList[*mapsCount].offset,
95 mapsList[*mapsCount].dev, &mapsList[*mapsCount].inode, mapsList[*mapsCount].name);
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +020096
97 *mapsCount += 1;
98 if ((mapsList = realloc(mapsList, (*mapsCount + 1) * sizeof(procMap_t))) == NULL) {
99 PLOG_W("realloc failed (sz=%zu)", (*mapsCount + 1) * sizeof(procMap_t));
100 free(mapsList);
101 return NULL;
102 }
103 }
104
105 return mapsList;
106}
107
Robert Swieckid50ed422017-11-13 23:32:26 +0100108static char* arch_searchMaps(unsigned long addr, size_t mapsCnt, procMap_t* mapsList) {
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +0200109 for (size_t i = 0; i < mapsCnt; i++) {
110 if (addr >= mapsList[i].start && addr <= mapsList[i].end) {
111 return mapsList[i].name;
112 }
113
114 /* Benefit from maps being sorted by address */
115 if (addr < mapsList[i].start) {
116 break;
117 }
118 }
119 return NULL;
120}
121
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300122#ifndef __ANDROID__
Robert Swieckid50ed422017-11-13 23:32:26 +0100123size_t arch_unwindStack(pid_t pid, funcs_t* funcs) {
Robert Swieckibbb476e2020-04-29 15:57:06 +0200124 size_t num_frames = 0, mapsCnt = 0;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200125 procMap_t* mapsList = arch_parsePidMaps(pid, &mapsCnt);
Robert Swiecki3ab16642018-01-12 18:08:37 +0100126 defer {
127 free(mapsList);
128 };
robert.swiecki@gmail.comd7123702015-02-16 14:50:50 +0000129
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000130 unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
131 if (!as) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200132 LOG_E("[pid='%d'] unw_create_addr_space failed", pid);
Jagger8e2979b2016-03-22 12:29:24 +0100133 return num_frames;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000134 }
Robert Swiecki3ab16642018-01-12 18:08:37 +0100135 defer {
136 unw_destroy_addr_space(as);
137 };
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000138
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200139 void* ui = _UPT_create(pid);
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000140 if (ui == NULL) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200141 LOG_E("[pid='%d'] _UPT_create failed", pid);
Jagger8e2979b2016-03-22 12:29:24 +0100142 return num_frames;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000143 }
Robert Swiecki3ab16642018-01-12 18:08:37 +0100144 defer {
145 _UPT_destroy(ui);
146 };
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000147
148 unw_cursor_t c;
Robert Swieckibbb476e2020-04-29 15:57:06 +0200149 int ret = unw_init_remote(&c, as, ui);
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300150 if (ret < 0) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200151 LOG_E("[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]);
Jagger8e2979b2016-03-22 12:29:24 +0100152 return num_frames;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000153 }
154
Anestis Bechtsoudis236ef462015-08-08 03:46:51 +0300155 for (num_frames = 0; unw_step(&c) > 0 && num_frames < _HF_MAX_FUNCS; num_frames++) {
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000156 unw_word_t ip;
Robert Swieckibbb476e2020-04-29 15:57:06 +0200157 char* module = NULL;
158 ret = unw_get_reg(&c, UNW_REG_IP, &ip);
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300159 if (ret < 0) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200160 LOG_E("[pid='%d'] [%zd] failed to read IP (%s)", pid, num_frames, UNW_ER[-ret]);
Anestis Bechtsoudis236ef462015-08-08 03:46:51 +0300161 funcs[num_frames].pc = 0;
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +0200162 } else {
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200163 funcs[num_frames].pc = (void*)(uintptr_t)ip;
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +0200164 }
Robert Swiecki9eafcc62019-12-05 15:53:39 +0100165 if (mapsCnt > 0 && (module = arch_searchMaps(ip, mapsCnt, mapsList)) != NULL) {
166 memcpy(funcs[num_frames].module, module, sizeof(funcs[num_frames].module));
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +0200167 } else {
Robert Swiecki9eafcc62019-12-05 15:53:39 +0100168 strncpy(funcs[num_frames].module, "UNKNOWN", sizeof(funcs[num_frames].module));
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +0200169 }
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000170 }
171
Anestis Bechtsoudis236ef462015-08-08 03:46:51 +0300172 return num_frames;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +0000173}
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300174
Robert Swieckid50ed422017-11-13 23:32:26 +0100175#else /* !defined(__ANDROID__) */
176size_t arch_unwindStack(pid_t pid, funcs_t* funcs) {
Robert Swieckibbb476e2020-04-29 15:57:06 +0200177 size_t num_frames = 0, mapsCnt = 0;
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200178 procMap_t* mapsList = arch_parsePidMaps(pid, &mapsCnt);
Robert Swiecki3ab16642018-01-12 18:08:37 +0100179 defer {
180 free(mapsList);
181 };
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +0200182
Jagger79e82d12016-03-22 12:27:03 +0100183 unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300184 if (!as) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200185 LOG_E("[pid='%d'] unw_create_addr_space failed", pid);
Jagger79e82d12016-03-22 12:27:03 +0100186 return num_frames;
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300187 }
Robert Swiecki3ab16642018-01-12 18:08:37 +0100188 defer {
189 unw_destroy_addr_space(as);
190 };
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300191
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200192 struct UPT_info* ui = (struct UPT_info*)_UPT_create(pid);
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300193 if (ui == NULL) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200194 LOG_E("[pid='%d'] _UPT_create failed", pid);
Jagger79e82d12016-03-22 12:27:03 +0100195 return num_frames;
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300196 }
Robert Swiecki3ab16642018-01-12 18:08:37 +0100197 defer {
198 _UPT_destroy(ui);
199 };
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300200
201 unw_cursor_t cursor;
Robert Swieckibbb476e2020-04-29 15:57:06 +0200202 int ret = unw_init_remote(&cursor, as, ui);
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300203 if (ret < 0) {
Robert Swieckic8c32db2015-10-09 18:06:22 +0200204 LOG_E("[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]);
Jagger79e82d12016-03-22 12:27:03 +0100205 return num_frames;
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300206 }
207
208 do {
Robert Swieckibbb476e2020-04-29 15:57:06 +0200209 char* module = NULL;
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300210 unw_word_t pc = 0, offset = 0;
Robert Swieckibbb476e2020-04-29 15:57:06 +0200211 char buf[_HF_FUNC_NAME_SZ] = {0};
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300212
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300213 ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
214 if (ret < 0) {
Anestis Bechtsoudisb48b4742015-10-11 20:12:57 -0700215 LOG_E("[pid='%d'] [%zd] failed to read IP (%s)", pid, num_frames, UNW_ER[-ret]);
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300216 // We don't want to try to extract info from an arbitrary IP
217 // TODO: Maybe abort completely (goto out))
218 goto skip_frame_info;
219 }
220
Anestis Bechtsoudisffe48dc2015-09-12 14:25:19 +0300221 unw_proc_info_t frameInfo;
222 ret = unw_get_proc_info(&cursor, &frameInfo);
223 if (ret < 0) {
Anestis Bechtsoudisb48b4742015-10-11 20:12:57 -0700224 LOG_D("[pid='%d'] [%zd] unw_get_proc_info (%s)", pid, num_frames, UNW_ER[-ret]);
Anestis Bechtsoudisffe48dc2015-09-12 14:25:19 +0300225 // Not safe to keep parsing frameInfo
226 goto skip_frame_info;
227 }
228
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300229 ret = unw_get_proc_name(&cursor, buf, sizeof(buf), &offset);
230 if (ret < 0) {
Robert Swiecki0b566112017-10-17 17:39:07 +0200231 LOG_D(
232 "[pid='%d'] [%zd] unw_get_proc_name() failed (%s)", pid, num_frames, UNW_ER[-ret]);
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300233 buf[0] = '\0';
234 }
235
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200236 skip_frame_info:
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300237 // Compared to bfd, line var plays the role of offset from func_name
238 // Reports format is adjusted accordingly to reflect in saved file
239 funcs[num_frames].line = offset;
Robert Swieckibbb476e2020-04-29 15:57:06 +0200240 funcs[num_frames].pc = (void*)pc;
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300241 memcpy(funcs[num_frames].func, buf, sizeof(funcs[num_frames].func));
Robert Swiecki9eafcc62019-12-05 15:53:39 +0100242 if (mapsCnt > 0 && (module = arch_searchMaps(pc, mapsCnt, mapsList)) != NULL) {
243 memcpy(funcs[num_frames].module, module, sizeof(funcs[num_frames].module));
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +0200244 } else {
Robert Swiecki9eafcc62019-12-05 15:53:39 +0100245 strncpy(funcs[num_frames].module, "UNKNOWN", sizeof(funcs[num_frames].module));
Anestis Bechtsoudis3b8d47e2016-10-30 12:04:20 +0200246 }
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300247
248 num_frames++;
249
250 ret = unw_step(&cursor);
251 } while (ret > 0 && num_frames < _HF_MAX_FUNCS);
252
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300253 return num_frames;
254}
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200255#endif /* defined(__ANDROID__) */
Anestis Bechtsoudisba68b382016-10-29 20:44:15 +0300256
257/*
258 * Nested loop not most efficient approach, although it's assumed that list is
259 * usually target specific and thus small.
260 */
Robert Swiecki0b566112017-10-17 17:39:07 +0200261char* arch_btContainsSymbol(
Robert Swieckid50ed422017-11-13 23:32:26 +0100262 size_t symbolsListSz, char** symbolsList, size_t num_frames, funcs_t* funcs) {
Anestis Bechtsoudisba68b382016-10-29 20:44:15 +0300263 for (size_t frame = 0; frame < num_frames; frame++) {
264 size_t len = strlen(funcs[frame].func);
265
266 /* Try only for frames that have symbol name from backtrace */
267 if (strlen(funcs[frame].func) > 0) {
268 for (size_t i = 0; i < symbolsListSz; i++) {
269 /* Wildcard symbol string special case */
Robert Swiecki4e595fb2017-10-11 17:26:51 +0200270 char* wOff = strchr(symbolsList[i], '*');
Anestis Bechtsoudisba68b382016-10-29 20:44:15 +0300271 if (wOff) {
272 /* Length always > 3 as checked at input file parsing step */
273 len = wOff - symbolsList[i] - 1;
274 }
275
276 if (strncmp(funcs[frame].func, symbolsList[i], len) == 0) {
277 return funcs[frame].func;
278 }
279 }
280 }
281 }
282 return NULL;
283}