• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define _GNU_SOURCE 1
18 #include <elf.h>
19 #include <inttypes.h>
20 #include <stdint.h>
21 #include <string.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 
25 #include <algorithm>
26 
27 #include <android-base/stringprintf.h>
28 
29 #include <unwindstack/Elf.h>
30 #include <unwindstack/JitDebug.h>
31 #include <unwindstack/MapInfo.h>
32 #include <unwindstack/Unwinder.h>
33 
34 #if !defined(NO_LIBDEXFILE_SUPPORT)
35 #include <unwindstack/DexFiles.h>
36 #endif
37 
38 namespace unwindstack {
39 
40 // Inject extra 'virtual' frame that represents the dex pc data.
41 // The dex pc is a magic register defined in the Mterp interpreter,
42 // and thus it will be restored/observed in the frame after it.
43 // Adding the dex frame first here will create something like:
44 //   #7 pc 0015fa20 core.vdex   java.util.Arrays.binarySearch+8
45 //   #8 pc 006b1ba1 libartd.so  ExecuteMterpImpl+14625
46 //   #9 pc 0039a1ef libartd.so  art::interpreter::Execute+719
FillInDexFrame()47 void Unwinder::FillInDexFrame() {
48   size_t frame_num = frames_.size();
49   frames_.resize(frame_num + 1);
50   FrameData* frame = &frames_.at(frame_num);
51   frame->num = frame_num;
52 
53   uint64_t dex_pc = regs_->dex_pc();
54   frame->pc = dex_pc;
55   frame->sp = regs_->sp();
56 
57   MapInfo* info = maps_->Find(dex_pc);
58   if (info != nullptr) {
59     frame->map_start = info->start;
60     frame->map_end = info->end;
61     frame->map_offset = info->offset;
62     frame->map_load_bias = info->load_bias;
63     frame->map_flags = info->flags;
64     frame->map_name = info->name;
65     frame->rel_pc = dex_pc - info->start;
66   } else {
67     frame->rel_pc = dex_pc;
68     return;
69   }
70 
71   if (!resolve_names_) {
72     return;
73   }
74 
75 #if !defined(NO_LIBDEXFILE_SUPPORT)
76   if (dex_files_ == nullptr) {
77     return;
78   }
79 
80   dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name,
81                                    &frame->function_offset);
82 #endif
83 }
84 
FillInFrame(MapInfo * map_info,Elf * elf,uint64_t rel_pc,uint64_t func_pc,uint64_t pc_adjustment)85 void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t func_pc,
86                            uint64_t pc_adjustment) {
87   size_t frame_num = frames_.size();
88   frames_.resize(frame_num + 1);
89   FrameData* frame = &frames_.at(frame_num);
90   frame->num = frame_num;
91   frame->sp = regs_->sp();
92   frame->rel_pc = rel_pc - pc_adjustment;
93   frame->pc = regs_->pc() - pc_adjustment;
94 
95   if (map_info == nullptr) {
96     return;
97   }
98 
99   frame->map_name = map_info->name;
100   frame->map_offset = map_info->offset;
101   frame->map_start = map_info->start;
102   frame->map_end = map_info->end;
103   frame->map_flags = map_info->flags;
104   frame->map_load_bias = elf->GetLoadBias();
105 
106   if (!resolve_names_ ||
107       !elf->GetFunctionName(func_pc, &frame->function_name, &frame->function_offset)) {
108     frame->function_name = "";
109     frame->function_offset = 0;
110   }
111 }
112 
ShouldStop(const std::vector<std::string> * map_suffixes_to_ignore,std::string & map_name)113 static bool ShouldStop(const std::vector<std::string>* map_suffixes_to_ignore,
114                        std::string& map_name) {
115   if (map_suffixes_to_ignore == nullptr) {
116     return false;
117   }
118   auto pos = map_name.find_last_of('.');
119   if (pos == std::string::npos) {
120     return false;
121   }
122 
123   return std::find(map_suffixes_to_ignore->begin(), map_suffixes_to_ignore->end(),
124                    map_name.substr(pos + 1)) != map_suffixes_to_ignore->end();
125 }
126 
Unwind(const std::vector<std::string> * initial_map_names_to_skip,const std::vector<std::string> * map_suffixes_to_ignore)127 void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
128                       const std::vector<std::string>* map_suffixes_to_ignore) {
129   frames_.clear();
130   last_error_.code = ERROR_NONE;
131   last_error_.address = 0;
132 
133   bool return_address_attempt = false;
134   bool adjust_pc = false;
135   std::unique_ptr<JitDebug> jit_debug;
136   for (; frames_.size() < max_frames_;) {
137     uint64_t cur_pc = regs_->pc();
138     uint64_t cur_sp = regs_->sp();
139 
140     MapInfo* map_info = maps_->Find(regs_->pc());
141     uint64_t rel_pc;
142     uint64_t pc_adjustment = 0;
143     uint64_t step_pc;
144     Elf* elf;
145     if (map_info == nullptr) {
146       rel_pc = regs_->pc();
147       step_pc = rel_pc;
148       last_error_.code = ERROR_INVALID_MAP;
149     } else {
150       if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
151         break;
152       }
153       elf = map_info->GetElf(process_memory_, true);
154       rel_pc = elf->GetRelPc(regs_->pc(), map_info);
155       if (adjust_pc) {
156         pc_adjustment = regs_->GetPcAdjustment(rel_pc, elf);
157       } else {
158         pc_adjustment = 0;
159       }
160       step_pc = rel_pc - pc_adjustment;
161 
162       // If the pc is in an invalid elf file, try and get an Elf object
163       // using the jit debug information.
164       if (!elf->valid() && jit_debug_ != nullptr) {
165         uint64_t adjusted_jit_pc = regs_->pc() - pc_adjustment;
166         Elf* jit_elf = jit_debug_->GetElf(maps_, adjusted_jit_pc);
167         if (jit_elf != nullptr) {
168           // The jit debug information requires a non relative adjusted pc.
169           step_pc = adjusted_jit_pc;
170           elf = jit_elf;
171         }
172       }
173     }
174 
175     if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
176         std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
177                   basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
178       if (regs_->dex_pc() != 0) {
179         // Add a frame to represent the dex file.
180         FillInDexFrame();
181         // Clear the dex pc so that we don't repeat this frame later.
182         regs_->set_dex_pc(0);
183       }
184 
185       FillInFrame(map_info, elf, rel_pc, step_pc, pc_adjustment);
186 
187       // Once a frame is added, stop skipping frames.
188       initial_map_names_to_skip = nullptr;
189     }
190     adjust_pc = true;
191 
192     bool stepped;
193     bool in_device_map = false;
194     if (map_info == nullptr) {
195       stepped = false;
196     } else {
197       if (map_info->flags & MAPS_FLAGS_DEVICE_MAP) {
198         // Do not stop here, fall through in case we are
199         // in the speculative unwind path and need to remove
200         // some of the speculative frames.
201         stepped = false;
202         in_device_map = true;
203       } else {
204         MapInfo* sp_info = maps_->Find(regs_->sp());
205         if (sp_info != nullptr && sp_info->flags & MAPS_FLAGS_DEVICE_MAP) {
206           // Do not stop here, fall through in case we are
207           // in the speculative unwind path and need to remove
208           // some of the speculative frames.
209           stepped = false;
210           in_device_map = true;
211         } else {
212           bool finished;
213           stepped = elf->Step(rel_pc, step_pc, regs_, process_memory_.get(), &finished);
214           elf->GetLastError(&last_error_);
215           if (stepped && finished) {
216             break;
217           }
218         }
219       }
220     }
221 
222     if (!stepped) {
223       if (return_address_attempt) {
224         // Remove the speculative frame.
225         frames_.pop_back();
226         break;
227       } else if (in_device_map) {
228         // Do not attempt any other unwinding, pc or sp is in a device
229         // map.
230         break;
231       } else {
232         // Steping didn't work, try this secondary method.
233         if (!regs_->SetPcFromReturnAddress(process_memory_.get())) {
234           break;
235         }
236         return_address_attempt = true;
237       }
238     } else {
239       return_address_attempt = false;
240       if (max_frames_ == frames_.size()) {
241         last_error_.code = ERROR_MAX_FRAMES_EXCEEDED;
242       }
243     }
244 
245     // If the pc and sp didn't change, then consider everything stopped.
246     if (cur_pc == regs_->pc() && cur_sp == regs_->sp()) {
247       last_error_.code = ERROR_REPEATED_FRAME;
248       break;
249     }
250   }
251 }
252 
FormatFrame(size_t frame_num)253 std::string Unwinder::FormatFrame(size_t frame_num) {
254   if (frame_num >= frames_.size()) {
255     return "";
256   }
257   return FormatFrame(frames_[frame_num], regs_->Is32Bit());
258 }
259 
FormatFrame(const FrameData & frame,bool is32bit)260 std::string Unwinder::FormatFrame(const FrameData& frame, bool is32bit) {
261   std::string data;
262 
263   if (is32bit) {
264     data += android::base::StringPrintf("  #%02zu pc %08" PRIx64, frame.num, frame.rel_pc);
265   } else {
266     data += android::base::StringPrintf("  #%02zu pc %016" PRIx64, frame.num, frame.rel_pc);
267   }
268 
269   if (frame.map_offset != 0) {
270     data += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", frame.map_offset);
271   }
272 
273   if (frame.map_start == frame.map_end) {
274     // No valid map associated with this frame.
275     data += "  <unknown>";
276   } else if (!frame.map_name.empty()) {
277     data += "  " + frame.map_name;
278   } else {
279     data += android::base::StringPrintf("  <anonymous:%" PRIx64 ">", frame.map_start);
280   }
281   if (!frame.function_name.empty()) {
282     data += " (" + frame.function_name;
283     if (frame.function_offset != 0) {
284       data += android::base::StringPrintf("+%" PRId64, frame.function_offset);
285     }
286     data += ')';
287   }
288   return data;
289 }
290 
SetJitDebug(JitDebug * jit_debug,ArchEnum arch)291 void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) {
292   jit_debug->SetArch(arch);
293   jit_debug_ = jit_debug;
294 }
295 
296 #if !defined(NO_LIBDEXFILE_SUPPORT)
SetDexFiles(DexFiles * dex_files,ArchEnum arch)297 void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) {
298   dex_files->SetArch(arch);
299   dex_files_ = dex_files;
300 }
301 #endif
302 
303 }  // namespace unwindstack
304