1 /*
2  *
3  * honggfuzz - architecture dependent code (LINUX/UNWIND)
4  * -----------------------------------------
5  *
6  * Author: Robert Swiecki <swiecki@google.com>
7  *
8  * Copyright 2010-2015 by Google Inc. All Rights Reserved.
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
12  * a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
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.
21  *
22  */
23 
24 #include "common.h"
25 #include "linux/unwind.h"
26 
27 #include <libunwind-ptrace.h>
28 
29 #include "log.h"
30 
31 #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 // libunwind error codes used for debugging
41 static const char *UNW_ER[] = {
42     "UNW_ESUCCESS",             /* no error */
43     "UNW_EUNSPEC",              /* unspecified (general) error */
44     "UNW_ENOMEM",               /* out of memory */
45     "UNW_EBADREG",              /* bad register number */
46     "UNW_EREADONLYREG",         /* attempt to write read-only register */
47     "UNW_ESTOPUNWIND",          /* stop unwinding */
48     "UNW_EINVALIDIP",           /* invalid IP */
49     "UNW_EBADFRAME",            /* bad frame */
50     "UNW_EINVAL",               /* unsupported operation or bad value */
51     "UNW_EBADVERSION",          /* unwind info has unsupported version */
52     "UNW_ENOINFO"               /* no unwind info found */
53 };
54 
55 #ifndef __ANDROID__
arch_unwindStack(pid_t pid,funcs_t * funcs)56 size_t arch_unwindStack(pid_t pid, funcs_t * funcs)
57 {
58     size_t num_frames = 0;
59     void *ui = NULL;
60 
61     unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
62     if (!as) {
63         LOG_E("[pid='%d'] unw_create_addr_space failed", pid);
64         goto out;
65     }
66 
67     ui = _UPT_create(pid);
68     if (ui == NULL) {
69         LOG_E("[pid='%d'] _UPT_create failed", pid);
70         goto out;
71     }
72 
73     unw_cursor_t c;
74     int ret = unw_init_remote(&c, as, ui);
75     if (ret < 0) {
76         LOG_E("[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]);
77         goto out;
78     }
79 
80     for (num_frames = 0; unw_step(&c) > 0 && num_frames < _HF_MAX_FUNCS; num_frames++) {
81         unw_word_t ip;
82         ret = unw_get_reg(&c, UNW_REG_IP, &ip);
83         if (ret < 0) {
84             LOG_E("[pid='%d'] [%zd] failed to read IP (%s)", pid, num_frames, UNW_ER[-ret]);
85             funcs[num_frames].pc = 0;
86         } else
87             funcs[num_frames].pc = (void *)ip;
88     }
89 
90  out:
91     ui ? _UPT_destroy(ui) : 0;
92     as ? unw_destroy_addr_space(as) : 0;
93 
94     return num_frames;
95 }
96 
97 #else                           /* !defined(__ANDROID__) */
arch_unwindStack(pid_t pid,funcs_t * funcs)98 size_t arch_unwindStack(pid_t pid, funcs_t * funcs)
99 {
100     size_t num_frames = 0;
101     struct UPT_info *ui = NULL;
102     unw_addr_space_t as = NULL;
103 
104     as = unw_create_addr_space(&_UPT_accessors, __BYTE_ORDER);
105     if (!as) {
106         LOG_E("[pid='%d'] unw_create_addr_space failed", pid);
107         goto out;
108     }
109 
110     ui = (struct UPT_info *)_UPT_create(pid);
111     if (ui == NULL) {
112         LOG_E("[pid='%d'] _UPT_create failed", pid);
113         goto out;
114     }
115 
116     unw_cursor_t cursor;
117     int ret = unw_init_remote(&cursor, as, ui);
118     if (ret < 0) {
119         LOG_E("[pid='%d'] unw_init_remote failed (%s)", pid, UNW_ER[-ret]);
120         goto out;
121     }
122 
123     do {
124         unw_word_t pc = 0, offset = 0;
125         char buf[_HF_FUNC_NAME_SZ] = { 0 };
126 
127         ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
128         if (ret < 0) {
129             LOG_E("[pid='%d'] [%zd] failed to read IP (%s)", pid, num_frames, UNW_ER[-ret]);
130             // We don't want to try to extract info from an arbitrary IP
131             // TODO: Maybe abort completely (goto out))
132             goto skip_frame_info;
133         }
134 
135         unw_proc_info_t frameInfo;
136         ret = unw_get_proc_info(&cursor, &frameInfo);
137         if (ret < 0) {
138             LOG_D("[pid='%d'] [%zd] unw_get_proc_info (%s)", pid, num_frames, UNW_ER[-ret]);
139             // Not safe to keep parsing frameInfo
140             goto skip_frame_info;
141         }
142 
143         ret = unw_get_proc_name(&cursor, buf, sizeof(buf), &offset);
144         if (ret < 0) {
145             LOG_D("[pid='%d'] [%zd] unw_get_proc_name() failed (%s)", pid, num_frames,
146                   UNW_ER[-ret]);
147             buf[0] = '\0';
148         }
149 
150  skip_frame_info:
151         // Compared to bfd, line var plays the role of offset from func_name
152         // Reports format is adjusted accordingly to reflect in saved file
153         funcs[num_frames].line = offset;
154         funcs[num_frames].pc = (void *)pc;
155         memcpy(funcs[num_frames].func, buf, sizeof(funcs[num_frames].func));
156 
157         num_frames++;
158 
159         ret = unw_step(&cursor);
160     } while (ret > 0 && num_frames < _HF_MAX_FUNCS);
161 
162  out:
163     ui ? _UPT_destroy(ui) : NULL;
164     as ? unw_destroy_addr_space(as) : NULL;
165 
166     ui = NULL;
167     as = NULL;
168 
169     return num_frames;
170 }
171 #endif                          /* defined(__ANDROID__) */
172