blob: 8a59e09fd34939c37e82c52da75b67fb1bbf030f [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 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/*
18 * Functions to deal with class definition structures in DEX files
19 */
20
21#include <stdlib.h>
22#include <string.h>
23#include "DexClass.h"
24#include "Leb128.h"
25
26/* Helper for verification which reads and verifies a given number
27 * of uleb128 values. */
28static bool verifyUlebs(const u1* pData, const u1* pLimit, u4 count) {
29 bool okay = true;
30 u4 i;
31
32 while (okay && (count-- != 0)) {
33 readAndVerifyUnsignedLeb128(&pData, pLimit, &okay);
34 }
35
36 return okay;
37}
38
39/* Read and verify the header of a class_data_item. This updates the
40 * given data pointer to point past the end of the read data and
41 * returns an "okay" flag (that is, false == failure). */
42bool dexReadAndVerifyClassDataHeader(const u1** pData, const u1* pLimit,
43 DexClassDataHeader *pHeader) {
44 if (! verifyUlebs(*pData, pLimit, 4)) {
45 return false;
46 }
47
48 dexReadClassDataHeader(pData, pHeader);
49 return true;
50}
51
52/* Read and verify an encoded_field. This updates the
53 * given data pointer to point past the end of the read data and
54 * returns an "okay" flag (that is, false == failure).
Carl Shapirode750892010-06-08 16:37:12 -070055 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080056 * The lastIndex value should be set to 0 before the first field in
57 * a list is read. It is updated as fields are read and used in the
58 * decode process.
Carl Shapirode750892010-06-08 16:37:12 -070059 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080060 * The verification done by this function is of the raw data format
61 * only; it does not verify that access flags or indices
62 * are valid. */
63bool dexReadAndVerifyClassDataField(const u1** pData, const u1* pLimit,
64 DexField* pField, u4* lastIndex) {
65 if (! verifyUlebs(*pData, pLimit, 2)) {
66 return false;
67 }
68
69 dexReadClassDataField(pData, pField, lastIndex);
70 return true;
71}
72
73/* Read and verify an encoded_method. This updates the
74 * given data pointer to point past the end of the read data and
75 * returns an "okay" flag (that is, false == failure).
Carl Shapirode750892010-06-08 16:37:12 -070076 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080077 * The lastIndex value should be set to 0 before the first method in
78 * a list is read. It is updated as fields are read and used in the
79 * decode process.
80 *
81 * The verification done by this function is of the raw data format
82 * only; it does not verify that access flags, indices, or offsets
83 * are valid. */
84bool dexReadAndVerifyClassDataMethod(const u1** pData, const u1* pLimit,
85 DexMethod* pMethod, u4* lastIndex) {
86 if (! verifyUlebs(*pData, pLimit, 3)) {
87 return false;
88 }
89
90 dexReadClassDataMethod(pData, pMethod, lastIndex);
91 return true;
92}
93
94/* Read, verify, and return an entire class_data_item. This updates
95 * the given data pointer to point past the end of the read data. This
96 * function allocates a single chunk of memory for the result, which
97 * must subsequently be free()d. This function returns NULL if there
98 * was trouble parsing the data. If this function is passed NULL, it
99 * returns an initialized empty DexClassData structure.
Carl Shapirode750892010-06-08 16:37:12 -0700100 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800101 * The verification done by this function is of the raw data format
102 * only; it does not verify that access flags, indices, or offsets
103 * are valid. */
104DexClassData* dexReadAndVerifyClassData(const u1** pData, const u1* pLimit) {
105 DexClassDataHeader header;
106 u4 lastIndex;
107
108 if (*pData == NULL) {
109 DexClassData* result = malloc(sizeof(DexClassData));
110 memset(result, 0, sizeof(*result));
111 return result;
112 }
Carl Shapirode750892010-06-08 16:37:12 -0700113
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800114 if (! dexReadAndVerifyClassDataHeader(pData, pLimit, &header)) {
115 return NULL;
116 }
117
118 size_t resultSize = sizeof(DexClassData) +
119 (header.staticFieldsSize * sizeof(DexField)) +
120 (header.instanceFieldsSize * sizeof(DexField)) +
121 (header.directMethodsSize * sizeof(DexMethod)) +
122 (header.virtualMethodsSize * sizeof(DexMethod));
123
124 DexClassData* result = malloc(resultSize);
125 u1* ptr = ((u1*) result) + sizeof(DexClassData);
126 bool okay = true;
127 u4 i;
128
129 if (result == NULL) {
130 return NULL;
131 }
132
133 result->header = header;
134
135 if (header.staticFieldsSize != 0) {
136 result->staticFields = (DexField*) ptr;
137 ptr += header.staticFieldsSize * sizeof(DexField);
138 } else {
139 result->staticFields = NULL;
140 }
Carl Shapirode750892010-06-08 16:37:12 -0700141
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800142 if (header.instanceFieldsSize != 0) {
143 result->instanceFields = (DexField*) ptr;
144 ptr += header.instanceFieldsSize * sizeof(DexField);
145 } else {
146 result->instanceFields = NULL;
147 }
Carl Shapirode750892010-06-08 16:37:12 -0700148
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800149 if (header.directMethodsSize != 0) {
150 result->directMethods = (DexMethod*) ptr;
151 ptr += header.directMethodsSize * sizeof(DexMethod);
152 } else {
153 result->directMethods = NULL;
154 }
Carl Shapirode750892010-06-08 16:37:12 -0700155
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800156 if (header.virtualMethodsSize != 0) {
157 result->virtualMethods = (DexMethod*) ptr;
158 } else {
159 result->virtualMethods = NULL;
160 }
161
162 lastIndex = 0;
163 for (i = 0; okay && (i < header.staticFieldsSize); i++) {
164 okay = dexReadAndVerifyClassDataField(pData, pLimit,
165 &result->staticFields[i], &lastIndex);
166 }
167
168 lastIndex = 0;
169 for (i = 0; okay && (i < header.instanceFieldsSize); i++) {
170 okay = dexReadAndVerifyClassDataField(pData, pLimit,
171 &result->instanceFields[i], &lastIndex);
172 }
173
174 lastIndex = 0;
175 for (i = 0; okay && (i < header.directMethodsSize); i++) {
176 okay = dexReadAndVerifyClassDataMethod(pData, pLimit,
177 &result->directMethods[i], &lastIndex);
178 }
Carl Shapirode750892010-06-08 16:37:12 -0700179
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800180 lastIndex = 0;
181 for (i = 0; okay && (i < header.virtualMethodsSize); i++) {
182 okay = dexReadAndVerifyClassDataMethod(pData, pLimit,
183 &result->virtualMethods[i], &lastIndex);
184 }
185
186 if (! okay) {
187 free(result);
188 return NULL;
189 }
190
191 return result;
192}