blob: 6a585f4168ec28f446cf97ee1c1e12c5a58dfeaa [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.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/unwind.h"
26
27#include <libunwind-ptrace.h>
28
29#include "log.h"
30
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +030031#if defined(__ANDROID__)
32#include <sys/endian.h> /* For __BYTE_ORDER */
33#endif
34
35/*
36 * WARNING: Ensure that _UPT-info structs are not shared between threads
37 * http://www.nongnu.org/libunwind/man/libunwind-ptrace(3).html
38 */
39
40/*
41 * TODO: Subtract from load map to have relative PC stored in report file.
42 * link_map seems to be the easiest road for that.
43 */
44
45// libunwind error codes used for debugging
46static const char *UNW_ER[] = {
47 "UNW_ESUCCESS", /* no error */
48 "UNW_EUNSPEC", /* unspecified (general) error */
49 "UNW_ENOMEM", /* out of memory */
50 "UNW_EBADREG", /* bad register number */
51 "UNW_EREADONLYREG", /* attempt to write read-only register */
52 "UNW_ESTOPUNWIND", /* stop unwinding */
53 "UNW_EINVALIDIP", /* invalid IP */
54 "UNW_EBADFRAME", /* bad frame */
55 "UNW_EINVAL", /* unsupported operation or bad value */
56 "UNW_EBADVERSION", /* unwind info has unsupported version */
57 "UNW_ENOINFO" /* no unwind info found */
58};
59
60#ifndef __ANDROID__
61size_t arch_unwindStack(pid_t pid, funcs_t *funcs)
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000062{
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +030063 size_t frames = 0;
robert.swiecki@gmail.comd7123702015-02-16 14:50:50 +000064 void *ui = NULL;
65
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000066 unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
67 if (!as) {
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +030068 LOGMSG(l_ERROR, "[pid='%d'] unw_create_addr_space failed", pid);
robert.swiecki@gmail.comd7123702015-02-16 14:50:50 +000069 goto out;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000070 }
71
robert.swiecki@gmail.comd7123702015-02-16 14:50:50 +000072 ui = _UPT_create(pid);
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000073 if (ui == NULL) {
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +030074 LOGMSG(l_ERROR, "[pid='%d'] _UPT_create failed", pid);
robert.swiecki@gmail.comd7123702015-02-16 14:50:50 +000075 goto out;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000076 }
77
78 unw_cursor_t c;
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +030079 int ret = unw_init_remote(&c, as, ui);
80 if (ret < 0) {
81 LOGMSG(l_ERROR, "[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]);
robert.swiecki@gmail.comd7123702015-02-16 14:50:50 +000082 goto out;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000083 }
84
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +030085 for (frames = 0; unw_step(&c) > 0 && frames < _HF_MAX_FUNCS; frames++) {
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000086 unw_word_t ip;
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +030087 ret = unw_get_reg(&c, UNW_REG_IP, &ip);
88 if (ret < 0) {
89 LOMGSG(l_ERROR, "[pid='%d'] [%d] failed to read IP (%s)", pid, frames, UNW_ER[-ret]);
90 funcs[ret].pc = 0;
91 }
92 else
93 funcs[ret].pc = (void *)ip;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000094 }
95
robert.swiecki@gmail.com62e34ae2015-03-05 03:39:32 +000096 out:
robert.swiecki@gmail.comd7123702015-02-16 14:50:50 +000097 ui ? _UPT_destroy(ui) : 0;
98 as ? unw_destroy_addr_space(as) : 0;
robert.swiecki@gmail.coma0d87142015-02-14 13:11:18 +000099 return ret;
100}
Anestis Bechtsoudiscfc39fb2015-08-06 10:31:36 +0300101
102#else /* !defined(__ANDROID__) */
103size_t arch_unwindStack(pid_t pid, funcs_t *funcs)
104{
105 size_t num_frames = 0;
106 struct UPT_info *ui = NULL;
107 unw_addr_space_t as = NULL;
108
109 as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
110 if (!as) {
111 LOGMSG(l_ERROR, "[pid='%d'] unw_create_addr_space failed", pid);
112 goto out;
113 }
114
115 ui = (struct UPT_info*)_UPT_create(pid);
116 if (ui == NULL) {
117 LOGMSG(l_ERROR, "[pid='%d'] _UPT_create failed", pid);
118 goto out;
119 }
120
121 unw_cursor_t cursor;
122 int ret = unw_init_remote(&cursor, as, ui);
123 if (ret < 0) {
124 LOGMSG(l_ERROR, "[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]);
125 goto out;
126 }
127
128 do {
129 unw_word_t pc = 0, offset = 0;
130 char buf[_HF_FUNC_NAME_SZ] = { 0 };
131
132 unw_proc_info_t frameInfo;
133 ret = unw_get_proc_info(&cursor, &frameInfo);
134 if (ret < 0) {
135 LOGMSG(l_DEBUG, "[pid='%d'] [%d] unw_get_proc_info (%s)",
136 pid, num_frames, UNW_ER[-ret]);
137 // Not safe to keep reading
138 goto out;
139 }
140
141 ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
142 if (ret < 0) {
143 LOGMSG(l_ERROR, "[pid='%d'] [%d] failed to read IP (%s)",
144 pid, num_frames, UNW_ER[-ret]);
145 // We don't want to try to extract info from an arbitrary IP
146 // TODO: Maybe abort completely (goto out))
147 goto skip_frame_info;
148 }
149
150 ret = unw_get_proc_name(&cursor, buf, sizeof(buf), &offset);
151 if (ret < 0) {
152 LOGMSG(l_DEBUG, "[pid='%d'] [%d] unw_get_proc_name() failed (%s)",
153 pid, num_frames, UNW_ER[-ret]);
154 buf[0] = '\0';
155 }
156
157skip_frame_info:
158 // Compared to bfd, line var plays the role of offset from func_name
159 // Reports format is adjusted accordingly to reflect in saved file
160 funcs[num_frames].line = offset;
161 funcs[num_frames].pc = (void *)pc;
162 memcpy(funcs[num_frames].func, buf, sizeof(funcs[num_frames].func));
163
164 num_frames++;
165
166 ret = unw_step(&cursor);
167 } while (ret > 0 && num_frames < _HF_MAX_FUNCS);
168
169 out:
170 ui ? _UPT_destroy(ui) : NULL;
171 as ? unw_destroy_addr_space(as) : NULL;
172
173 ui = NULL;
174 as = NULL;
175
176 return num_frames;
177}
178#endif /* defined(__ANDROID__) */