1 /*
2  * Copyright (C) 2013 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 #ifndef ART_RUNTIME_MAPPING_TABLE_H_
18 #define ART_RUNTIME_MAPPING_TABLE_H_
19 
20 #include "base/logging.h"
21 #include "leb128.h"
22 
23 namespace art {
24 
25 // A utility for processing the raw uleb128 encoded mapping table created by the quick compiler.
26 class MappingTable {
27  public:
MappingTable(const uint8_t * encoded_map)28   explicit MappingTable(const uint8_t* encoded_map) : encoded_table_(encoded_map) {
29   }
30 
TotalSize()31   uint32_t TotalSize() const PURE {
32     const uint8_t* table = encoded_table_;
33     if (table == nullptr) {
34       return 0;
35     } else {
36       return DecodeUnsignedLeb128(&table);
37     }
38   }
39 
DexToPcSize()40   uint32_t DexToPcSize() const PURE {
41     const uint8_t* table = encoded_table_;
42     if (table == nullptr) {
43       return 0;
44     } else {
45       uint32_t total_size = DecodeUnsignedLeb128(&table);
46       uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table);
47       return total_size - pc_to_dex_size;
48     }
49   }
50 
FirstDexToPcPtr()51   const uint8_t* FirstDexToPcPtr() const {
52     const uint8_t* table = encoded_table_;
53     if (table != nullptr) {
54       uint32_t total_size = DecodeUnsignedLeb128(&table);
55       uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table);
56       // We must have dex to pc entries or else the loop will go beyond the end of the table.
57       DCHECK_GT(total_size, pc_to_dex_size);
58       for (uint32_t i = 0; i < pc_to_dex_size; ++i) {
59         DecodeUnsignedLeb128(&table);  // Move ptr past native PC delta.
60         DecodeSignedLeb128(&table);  // Move ptr past dex PC delta.
61       }
62     }
63     return table;
64   }
65 
66   class DexToPcIterator {
67    public:
DexToPcIterator(const MappingTable * table,uint32_t element)68     DexToPcIterator(const MappingTable* table, uint32_t element) :
69         table_(table), element_(element), end_(table_->DexToPcSize()), encoded_table_ptr_(nullptr),
70         native_pc_offset_(0), dex_pc_(0) {
71       if (element == 0) {  // An iterator wanted from the start.
72         if (end_ > 0) {
73           encoded_table_ptr_ = table_->FirstDexToPcPtr();
74           native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
75           // First delta is always positive.
76           dex_pc_ = static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
77         }
78       } else {  // An iterator wanted from the end.
79         DCHECK_EQ(table_->DexToPcSize(), element);
80       }
81     }
NativePcOffset()82     uint32_t NativePcOffset() const {
83       return native_pc_offset_;
84     }
DexPc()85     uint32_t DexPc() const {
86       return dex_pc_;
87     }
88     void operator++() {
89       ++element_;
90       if (element_ != end_) {  // Avoid reading beyond the end of the table.
91         native_pc_offset_ += DecodeUnsignedLeb128(&encoded_table_ptr_);
92         // For negative delta, unsigned overflow after static_cast does exactly what we need.
93         dex_pc_ += static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
94       }
95     }
96     bool operator==(const DexToPcIterator& rhs) const {
97       CHECK(table_ == rhs.table_);
98       return element_ == rhs.element_;
99     }
100     bool operator!=(const DexToPcIterator& rhs) const {
101       CHECK(table_ == rhs.table_);
102       return element_ != rhs.element_;
103     }
104 
105    private:
106     const MappingTable* const table_;  // The original table.
107     uint32_t element_;  // A value in the range 0 to end_.
108     const uint32_t end_;  // Equal to table_->DexToPcSize().
109     const uint8_t* encoded_table_ptr_;  // Either null or points to encoded data after this entry.
110     uint32_t native_pc_offset_;  // The current value of native pc offset.
111     uint32_t dex_pc_;  // The current value of dex pc.
112   };
113 
DexToPcBegin()114   DexToPcIterator DexToPcBegin() const {
115     return DexToPcIterator(this, 0);
116   }
117 
DexToPcEnd()118   DexToPcIterator DexToPcEnd() const {
119     uint32_t size = DexToPcSize();
120     return DexToPcIterator(this, size);
121   }
122 
PcToDexSize()123   uint32_t PcToDexSize() const PURE {
124     const uint8_t* table = encoded_table_;
125     if (table == nullptr) {
126       return 0;
127     } else {
128       DecodeUnsignedLeb128(&table);  // Total_size, unused.
129       uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table);
130       return pc_to_dex_size;
131     }
132   }
133 
FirstPcToDexPtr()134   const uint8_t* FirstPcToDexPtr() const {
135     const uint8_t* table = encoded_table_;
136     if (table != nullptr) {
137       DecodeUnsignedLeb128(&table);  // Total_size, unused.
138       DecodeUnsignedLeb128(&table);  // PC to Dex size, unused.
139     }
140     return table;
141   }
142 
143   class PcToDexIterator {
144    public:
PcToDexIterator(const MappingTable * table,uint32_t element)145     PcToDexIterator(const MappingTable* table, uint32_t element) :
146         table_(table), element_(element), end_(table_->PcToDexSize()), encoded_table_ptr_(nullptr),
147         native_pc_offset_(0), dex_pc_(0) {
148       if (element == 0) {  // An iterator wanted from the start.
149         if (end_ > 0) {
150           encoded_table_ptr_ = table_->FirstPcToDexPtr();
151           native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
152           // First delta is always positive.
153           dex_pc_ = static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
154         }
155       } else {  // An iterator wanted from the end.
156         DCHECK_EQ(table_->PcToDexSize(), element);
157       }
158     }
NativePcOffset()159     uint32_t NativePcOffset() const {
160       return native_pc_offset_;
161     }
DexPc()162     uint32_t DexPc() const {
163       return dex_pc_;
164     }
165     void operator++() {
166       ++element_;
167       if (element_ != end_) {  // Avoid reading beyond the end of the table.
168         native_pc_offset_ += DecodeUnsignedLeb128(&encoded_table_ptr_);
169         // For negative delta, unsigned overflow after static_cast does exactly what we need.
170         dex_pc_ += static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
171       }
172     }
173     bool operator==(const PcToDexIterator& rhs) const {
174       CHECK(table_ == rhs.table_);
175       return element_ == rhs.element_;
176     }
177     bool operator!=(const PcToDexIterator& rhs) const {
178       CHECK(table_ == rhs.table_);
179       return element_ != rhs.element_;
180     }
181 
182    private:
183     const MappingTable* const table_;  // The original table.
184     uint32_t element_;  // A value in the range 0 to PcToDexSize.
185     const uint32_t end_;  // Equal to table_->PcToDexSize().
186     const uint8_t* encoded_table_ptr_;  // Either null or points to encoded data after this entry.
187     uint32_t native_pc_offset_;  // The current value of native pc offset.
188     uint32_t dex_pc_;  // The current value of dex pc.
189   };
190 
PcToDexBegin()191   PcToDexIterator PcToDexBegin() const {
192     return PcToDexIterator(this, 0);
193   }
194 
PcToDexEnd()195   PcToDexIterator PcToDexEnd() const {
196     uint32_t size = PcToDexSize();
197     return PcToDexIterator(this, size);
198   }
199 
200  private:
201   const uint8_t* const encoded_table_;
202 };
203 
204 }  // namespace art
205 
206 #endif  // ART_RUNTIME_MAPPING_TABLE_H_
207