1 /*
2  * Copyright (C) 2016 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 #pragma once
18 
19 #include <stddef.h>
20 #include <stdint.h>
21 
22 #include <iterator>
23 #include <map>
24 #include <memory>
25 #include <optional>
26 #include <unordered_map>
27 #include <utility>
28 #include <vector>
29 
30 #include <unwindstack/DwarfError.h>
31 #include <unwindstack/DwarfLocation.h>
32 #include <unwindstack/DwarfMemory.h>
33 #include <unwindstack/DwarfStructs.h>
34 
35 namespace unwindstack {
36 
37 // Forward declarations.
38 enum ArchEnum : uint8_t;
39 class Memory;
40 class Regs;
41 template <typename AddressType>
42 struct RegsInfo;
43 struct SectionInfo;
44 
45 class DwarfSection {
46  public:
47   DwarfSection(std::shared_ptr<Memory>& memory);
48   virtual ~DwarfSection() = default;
49 
50   class iterator {
51    public:
52     using iterator_category = std::bidirectional_iterator_tag;
53     using value_type = DwarfFde*;
54     using difference_type = ptrdiff_t;
55     using pointer = DwarfFde**;
56     using reference = DwarfFde*&;
57 
iterator(DwarfSection * section,size_t index)58     iterator(DwarfSection* section, size_t index) : index_(index) {
59       section->GetFdes(&fdes_);
60       if (index_ == static_cast<size_t>(-1)) {
61         index_ = fdes_.size();
62       }
63     }
64 
65     iterator& operator++() {
66       index_++;
67       return *this;
68     }
69     iterator& operator++(int increment) {
70       index_ += increment;
71       return *this;
72     }
73     iterator& operator--() {
74       index_--;
75       return *this;
76     }
77     iterator& operator--(int decrement) {
78       index_ -= decrement;
79       return *this;
80     }
81 
82     bool operator==(const iterator& rhs) const { return this->index_ == rhs.index_; }
83     bool operator!=(const iterator& rhs) const { return this->index_ != rhs.index_; }
84 
85     const DwarfFde* operator*() {
86       if (index_ > fdes_.size()) return nullptr;
87       return fdes_[index_];
88     }
89 
90    private:
91     std::vector<const DwarfFde*> fdes_;
92     size_t index_ = 0;
93   };
94 
begin()95   iterator begin() { return iterator(this, 0); }
end()96   iterator end() { return iterator(this, static_cast<size_t>(-1)); }
97 
LastErrorCode()98   DwarfErrorCode LastErrorCode() { return last_error_.code; }
LastErrorAddress()99   uint64_t LastErrorAddress() { return last_error_.address; }
100 
101   virtual bool Init(const SectionInfo& info) = 0;
102 
103   virtual bool Eval(const DwarfCie*, Memory*, const DwarfLocations&, Regs*, bool*) = 0;
104 
105   virtual bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde, ArchEnum arch) = 0;
106 
107   virtual void GetFdes(std::vector<const DwarfFde*>* fdes) = 0;
108 
109   virtual const DwarfFde* GetFdeFromPc(uint64_t pc) = 0;
110 
111   virtual bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, DwarfLocations* loc_regs,
112                                   ArchEnum arch) = 0;
113 
114   virtual uint64_t GetCieOffsetFromFde32(uint32_t pointer) = 0;
115 
116   virtual uint64_t GetCieOffsetFromFde64(uint64_t pointer) = 0;
117 
118   virtual uint64_t AdjustPcFromFde(uint64_t pc) = 0;
119 
120   bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished, bool* is_signal_frame);
121 
122  protected:
123   DwarfMemory memory_;
124   DwarfErrorData last_error_{DWARF_ERROR_NONE, 0};
125 
126   uint32_t cie32_value_ = 0;
127   uint64_t cie64_value_ = 0;
128 
129   std::unordered_map<uint64_t, DwarfFde> fde_entries_;
130   std::unordered_map<uint64_t, DwarfCie> cie_entries_;
131   std::unordered_map<uint64_t, DwarfLocations> cie_loc_regs_;
132   std::map<uint64_t, DwarfLocations> loc_regs_;  // Single row indexed by pc_end.
133 };
134 
135 template <typename AddressType>
136 class DwarfSectionImpl : public DwarfSection {
137  public:
DwarfSectionImpl(std::shared_ptr<Memory> & memory)138   DwarfSectionImpl(std::shared_ptr<Memory>& memory) : DwarfSection(memory) {}
139   virtual ~DwarfSectionImpl() = default;
140 
141   bool Init(const SectionInfo& info) override;
142 
143   const DwarfCie* GetCieFromOffset(uint64_t offset);
144 
145   const DwarfFde* GetFdeFromOffset(uint64_t offset);
146 
147   const DwarfFde* GetFdeFromPc(uint64_t pc) override;
148 
149   void GetFdes(std::vector<const DwarfFde*>* fdes) override;
150 
151   bool EvalRegister(const DwarfLocation* loc, uint32_t reg, AddressType* reg_ptr, void* info);
152 
153   bool Eval(const DwarfCie* cie, Memory* regular_memory, const DwarfLocations& loc_regs, Regs* regs,
154             bool* finished) override;
155 
156   bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, DwarfLocations* loc_regs,
157                           ArchEnum arch) override;
158 
159   bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde, ArchEnum arch) override;
160 
161  protected:
162   using DwarfFdeMap =
163       std::map</*end*/ uint64_t, std::pair</*start*/ uint64_t, /*offset*/ uint64_t>>;
164 
165   bool GetNextCieOrFde(/*inout*/ uint64_t& offset, /*out*/ std::optional<DwarfFde>& fde);
166 
167   bool FillInCieHeader(DwarfCie* cie);
168 
169   bool FillInCie(DwarfCie* cie);
170 
171   bool FillInFdeHeader(DwarfFde* fde);
172 
173   bool FillInFde(DwarfFde* fde);
174 
175   bool EvalExpression(const DwarfLocation& loc, Memory* regular_memory, AddressType* value,
176                       RegsInfo<AddressType>* regs_info, bool* is_dex_pc);
177 
178   static void InsertFde(uint64_t fde_offset, const DwarfFde* fde, /*out*/ DwarfFdeMap& fdes);
179 
180   void BuildFdeIndex();
181 
182   int64_t section_bias_ = 0;
183   uint64_t entries_offset_ = 0;
184   uint64_t entries_end_ = 0;
185   uint64_t pc_offset_ = 0;
186 
187   // Binary search table (similar to .eh_frame_hdr). Contains only FDE offsets to save memory.
188   std::vector<std::pair</*function end address*/ uint64_t, /*FDE offset*/ uint64_t>> fde_index_;
189 };
190 
191 }  // namespace unwindstack
192