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  * Header file of an in-memory representation of DEX files.
17  */
18 
19 #ifndef ART_DEXLAYOUT_DEX_WRITER_H_
20 #define ART_DEXLAYOUT_DEX_WRITER_H_
21 
22 #include <functional>
23 #include <memory>  // For unique_ptr
24 
25 #include "base/os.h"
26 #include "base/unix_file/fd_file.h"
27 #include "dex/compact_dex_level.h"
28 #include "dex_container.h"
29 #include "dex/dex_file.h"
30 #include "dex_ir.h"
31 
32 #include <queue>
33 
34 namespace art {
35 
36 class DexLayout;
37 class DexLayoutHotnessInfo;
38 
39 struct MapItem {
40   // Not using DexFile::MapItemType since compact dex and standard dex file may have different
41   // sections.
42   MapItem() = default;
MapItemMapItem43   MapItem(uint32_t type, uint32_t size, size_t offset)
44       : type_(type), size_(size), offset_(offset) { }
45 
46   // Sort by decreasing order since the priority_queue puts largest elements first.
47   bool operator>(const MapItem& other) const {
48     return offset_ > other.offset_;
49   }
50 
51   uint32_t type_ = 0u;
52   uint32_t size_ = 0u;
53   uint32_t offset_ = 0u;
54 };
55 
56 class MapItemQueue : public
57     std::priority_queue<MapItem, std::vector<MapItem>, std::greater<MapItem>> {
58  public:
59   void AddIfNotEmpty(const MapItem& item);
60 };
61 
62 class DexWriter {
63  public:
64   static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2;
65   static constexpr uint32_t kDexSectionWordAlignment = 4;
66 
67   // Stream that writes into a dex container section. Do not have two streams pointing to the same
68   // backing storage as there may be invalidation of backing storage to resize the section.
69   // Random access stream (consider refactoring).
70   class Stream {
71    public:
Stream(DexContainer::Section * section)72     explicit Stream(DexContainer::Section* section) : section_(section) {
73       SyncWithSection();
74     }
75 
Begin()76     const uint8_t* Begin() const {
77       return data_;
78     }
79 
80     // Functions are not virtual (yet) for speed.
Tell()81     size_t Tell() const {
82       return position_;
83     }
84 
Seek(size_t position)85     void Seek(size_t position) {
86       position_ = position;
87       EnsureStorage(0u);
88     }
89 
90     // Does not allow overwriting for bug prevention purposes.
Write(const void * buffer,size_t length)91     ALWAYS_INLINE size_t Write(const void* buffer, size_t length) {
92       EnsureStorage(length);
93       for (size_t i = 0; i < length; ++i) {
94         DCHECK_EQ(data_[position_ + i], 0u);
95       }
96       memcpy(&data_[position_], buffer, length);
97       position_ += length;
98       return length;
99     }
100 
Overwrite(const void * buffer,size_t length)101     ALWAYS_INLINE size_t Overwrite(const void* buffer, size_t length) {
102       EnsureStorage(length);
103       memcpy(&data_[position_], buffer, length);
104       position_ += length;
105       return length;
106     }
107 
Clear(size_t position,size_t length)108     ALWAYS_INLINE size_t Clear(size_t position, size_t length) {
109       EnsureStorage(length);
110       memset(&data_[position], 0, length);
111       return length;
112     }
113 
WriteSleb128(int32_t value)114     ALWAYS_INLINE size_t WriteSleb128(int32_t value) {
115       EnsureStorage(8);
116       uint8_t* ptr = &data_[position_];
117       const size_t len = EncodeSignedLeb128(ptr, value) - ptr;
118       position_ += len;
119       return len;
120     }
121 
WriteUleb128(uint32_t value)122     ALWAYS_INLINE size_t WriteUleb128(uint32_t value) {
123       EnsureStorage(8);
124       uint8_t* ptr = &data_[position_];
125       const size_t len = EncodeUnsignedLeb128(ptr, value) - ptr;
126       position_ += len;
127       return len;
128     }
129 
AlignTo(const size_t alignment)130     ALWAYS_INLINE void AlignTo(const size_t alignment) {
131       position_ = RoundUp(position_, alignment);
132       EnsureStorage(0u);
133     }
134 
Skip(const size_t count)135     ALWAYS_INLINE void Skip(const size_t count) {
136       position_ += count;
137       EnsureStorage(0u);
138     }
139 
140     class ScopedSeek {
141      public:
ScopedSeek(Stream * stream,uint32_t offset)142       ScopedSeek(Stream* stream, uint32_t offset) : stream_(stream), offset_(stream->Tell()) {
143         stream->Seek(offset);
144       }
145 
~ScopedSeek()146       ~ScopedSeek() {
147         stream_->Seek(offset_);
148       }
149 
150      private:
151       Stream* const stream_;
152       const uint32_t offset_;
153     };
154 
155    private:
EnsureStorage(size_t length)156     ALWAYS_INLINE void EnsureStorage(size_t length) {
157       size_t end = position_ + length;
158       while (UNLIKELY(end > data_size_)) {
159         section_->Resize(data_size_ * 3 / 2 + 1);
160         SyncWithSection();
161       }
162     }
163 
SyncWithSection()164     void SyncWithSection() {
165       data_ = section_->Begin();
166       data_size_ = section_->Size();
167     }
168 
169     // Current position of the stream.
170     size_t position_ = 0u;
171     DexContainer::Section* const section_ = nullptr;
172     // Cached Begin() from the container to provide faster accesses.
173     uint8_t* data_ = nullptr;
174     // Cached Size from the container to provide faster accesses.
175     size_t data_size_ = 0u;
176   };
177 
SectionAlignment(DexFile::MapItemType type)178   static inline constexpr uint32_t SectionAlignment(DexFile::MapItemType type) {
179     switch (type) {
180       case DexFile::kDexTypeClassDataItem:
181       case DexFile::kDexTypeStringDataItem:
182       case DexFile::kDexTypeDebugInfoItem:
183       case DexFile::kDexTypeAnnotationItem:
184       case DexFile::kDexTypeEncodedArrayItem:
185         return alignof(uint8_t);
186 
187       default:
188         // All other sections are kDexAlignedSection.
189         return DexWriter::kDexSectionWordAlignment;
190     }
191   }
192 
193   class Container : public DexContainer {
194    public:
GetMainSection()195     Section* GetMainSection() override {
196       return &main_section_;
197     }
198 
GetDataSection()199     Section* GetDataSection() override {
200       return &data_section_;
201     }
202 
IsCompactDexContainer()203     bool IsCompactDexContainer() const override {
204       return false;
205     }
206 
207    private:
208     VectorSection main_section_;
209     VectorSection data_section_;
210 
211     friend class CompactDexWriter;
212   };
213 
214   DexWriter(DexLayout* dex_layout, bool compute_offsets);
215 
216   static bool Output(DexLayout* dex_layout,
217                      std::unique_ptr<DexContainer>* container,
218                      bool compute_offsets,
219                      std::string* error_msg) WARN_UNUSED;
220 
~DexWriter()221   virtual ~DexWriter() {}
222 
223  protected:
224   virtual bool Write(DexContainer* output, std::string* error_msg);
225   virtual std::unique_ptr<DexContainer> CreateDexContainer() const;
226 
227   void WriteEncodedValue(Stream* stream, dex_ir::EncodedValue* encoded_value);
228   void WriteEncodedValueHeader(Stream* stream, int8_t value_type, size_t value_arg);
229   void WriteEncodedArray(Stream* stream, dex_ir::EncodedValueVector* values);
230   void WriteEncodedAnnotation(Stream* stream, dex_ir::EncodedAnnotation* annotation);
231   void WriteEncodedFields(Stream* stream, dex_ir::FieldItemVector* fields);
232   void WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* methods);
233 
234   // Header and id section
235   virtual void WriteHeader(Stream* stream);
236   virtual size_t GetHeaderSize() const;
237   // reserve_only means don't write, only reserve space. This is required since the string data
238   // offsets must be assigned.
239   void WriteStringIds(Stream* stream, bool reserve_only);
240   void WriteTypeIds(Stream* stream);
241   void WriteProtoIds(Stream* stream, bool reserve_only);
242   void WriteFieldIds(Stream* stream);
243   void WriteMethodIds(Stream* stream);
244   void WriteClassDefs(Stream* stream, bool reserve_only);
245   void WriteCallSiteIds(Stream* stream, bool reserve_only);
246 
247   void WriteEncodedArrays(Stream* stream);
248   void WriteAnnotations(Stream* stream);
249   void WriteAnnotationSets(Stream* stream);
250   void WriteAnnotationSetRefs(Stream* stream);
251   void WriteAnnotationsDirectories(Stream* stream);
252 
253   // Data section.
254   void WriteDebugInfoItems(Stream* stream);
255   void WriteCodeItems(Stream* stream, bool reserve_only);
256   void WriteTypeLists(Stream* stream);
257   void WriteStringDatas(Stream* stream);
258   void WriteClassDatas(Stream* stream);
259   void WriteMethodHandles(Stream* stream);
260   void WriteHiddenapiClassData(Stream* stream);
261   void WriteMapItems(Stream* stream, MapItemQueue* queue);
262   void GenerateAndWriteMapItems(Stream* stream);
263 
264   virtual void WriteCodeItemPostInstructionData(Stream* stream,
265                                                     dex_ir::CodeItem* item,
266                                                     bool reserve_only);
267   virtual void WriteCodeItem(Stream* stream, dex_ir::CodeItem* item, bool reserve_only);
268   virtual void WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info);
269   virtual void WriteStringData(Stream* stream, dex_ir::StringData* string_data);
270 
271   // Process an offset, if compute_offset is set, write into the dex ir item, otherwise read the
272   // existing offset and use that for writing.
273   void ProcessOffset(Stream* stream, dex_ir::Item* item);
274   void ProcessOffset(Stream* stream, dex_ir::CollectionBase* item);
275 
276   dex_ir::Header* const header_;
277   DexLayout* const dex_layout_;
278   bool compute_offsets_;
279 
280  private:
281   DISALLOW_COPY_AND_ASSIGN(DexWriter);
282 };
283 
284 }  // namespace art
285 
286 #endif  // ART_DEXLAYOUT_DEX_WRITER_H_
287