• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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_LIBDEXFILE_DEX_DEX_FILE_INL_H_
18 #define ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_
19 
20 #include "dex_file.h"
21 
22 #include "base/casts.h"
23 #include "base/iteration_range.h"
24 #include "base/leb128.h"
25 #include "base/utils.h"
26 #include "class_iterator.h"
27 #include "compact_dex_file.h"
28 #include "dex_instruction_iterator.h"
29 #include "invoke_type.h"
30 #include "signature.h"
31 #include "standard_dex_file.h"
32 
33 namespace art {
34 
StringViewFromUtf16Length(const char * utf8_data,size_t utf16_length)35 inline std::string_view StringViewFromUtf16Length(const char* utf8_data, size_t utf16_length) {
36   size_t utf8_length = LIKELY(utf8_data[utf16_length] == 0)  // Is ASCII?
37                            ? utf16_length
38                            : utf16_length + strlen(utf8_data + utf16_length);
39   return std::string_view(utf8_data, utf8_length);
40 }
41 
GetStringLength(const dex::StringId & string_id)42 inline int32_t DexFile::GetStringLength(const dex::StringId& string_id) const {
43   const uint8_t* ptr = DataBegin() + string_id.string_data_off_;
44   return DecodeUnsignedLeb128(&ptr);
45 }
46 
47 ALWAYS_INLINE
GetStringDataAndUtf16Length(const dex::StringId & string_id,uint32_t * utf16_length)48 inline const char* DexFile::GetStringDataAndUtf16Length(const dex::StringId& string_id,
49                                                         uint32_t* utf16_length) const {
50   DCHECK(utf16_length != nullptr) << GetLocation();
51   const uint8_t* ptr = DataBegin() + string_id.string_data_off_;
52   *utf16_length = DecodeUnsignedLeb128(&ptr);
53   return reinterpret_cast<const char*>(ptr);
54 }
55 
56 ALWAYS_INLINE
GetStringData(const dex::StringId & string_id)57 inline const char* DexFile::GetStringData(const dex::StringId& string_id) const {
58   uint32_t ignored;
59   return GetStringDataAndUtf16Length(string_id, &ignored);
60 }
61 
62 ALWAYS_INLINE
StringDataAndUtf16LengthByIdx(dex::StringIndex idx,uint32_t * utf16_length)63 inline const char* DexFile::StringDataAndUtf16LengthByIdx(dex::StringIndex idx,
64                                                           uint32_t* utf16_length) const {
65   if (!idx.IsValid()) {
66     *utf16_length = 0;
67     return nullptr;
68   }
69   const dex::StringId& string_id = GetStringId(idx);
70   return GetStringDataAndUtf16Length(string_id, utf16_length);
71 }
72 
73 ALWAYS_INLINE
StringDataByIdx(dex::StringIndex idx)74 inline const char* DexFile::StringDataByIdx(dex::StringIndex idx) const {
75   uint32_t unicode_length;
76   return StringDataAndUtf16LengthByIdx(idx, &unicode_length);
77 }
78 
79 ALWAYS_INLINE
StringViewByIdx(dex::StringIndex idx)80 inline std::string_view DexFile::StringViewByIdx(dex::StringIndex idx) const {
81   uint32_t unicode_length;
82   const char* data = StringDataAndUtf16LengthByIdx(idx, &unicode_length);
83   return data != nullptr ? StringViewFromUtf16Length(data, unicode_length) : std::string_view("");
84 }
85 
StringByTypeIdx(dex::TypeIndex idx,uint32_t * unicode_length)86 inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const {
87   if (!idx.IsValid()) {
88     return nullptr;
89   }
90   const dex::TypeId& type_id = GetTypeId(idx);
91   return StringDataAndUtf16LengthByIdx(type_id.descriptor_idx_, unicode_length);
92 }
93 
StringByTypeIdx(dex::TypeIndex idx)94 inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx) const {
95   if (!idx.IsValid()) {
96     return nullptr;
97   }
98   const dex::TypeId& type_id = GetTypeId(idx);
99   return StringDataByIdx(type_id.descriptor_idx_);
100 }
101 
GetTypeDescriptor(const dex::TypeId & type_id)102 inline const char* DexFile::GetTypeDescriptor(const dex::TypeId& type_id) const {
103   return StringDataByIdx(type_id.descriptor_idx_);
104 }
105 
GetTypeDescriptorView(const dex::TypeId & type_id)106 inline std::string_view DexFile::GetTypeDescriptorView(const dex::TypeId& type_id) const {
107   return StringViewByIdx(type_id.descriptor_idx_);
108 }
109 
GetFieldTypeDescriptor(const dex::FieldId & field_id)110 inline const char* DexFile::GetFieldTypeDescriptor(const dex::FieldId& field_id) const {
111   const dex::TypeId& type_id = GetTypeId(field_id.type_idx_);
112   return GetTypeDescriptor(type_id);
113 }
114 
GetFieldTypeDescriptorView(const dex::FieldId & field_id)115 inline std::string_view DexFile::GetFieldTypeDescriptorView(const dex::FieldId& field_id) const {
116   const dex::TypeId& type_id = GetTypeId(field_id.type_idx_);
117   return GetTypeDescriptorView(type_id);
118 }
119 
GetFieldName(const dex::FieldId & field_id)120 inline const char* DexFile::GetFieldName(const dex::FieldId& field_id) const {
121   return StringDataByIdx(field_id.name_idx_);
122 }
123 
GetFieldNameView(const dex::FieldId & field_id)124 inline std::string_view DexFile::GetFieldNameView(const dex::FieldId& field_id) const {
125   return StringViewByIdx(field_id.name_idx_);
126 }
127 
GetMethodDeclaringClassDescriptor(const dex::MethodId & method_id)128 inline const char* DexFile::GetMethodDeclaringClassDescriptor(const dex::MethodId& method_id)
129     const {
130   const dex::TypeId& type_id = GetTypeId(method_id.class_idx_);
131   return GetTypeDescriptor(type_id);
132 }
133 
GetMethodSignature(const dex::MethodId & method_id)134 inline const Signature DexFile::GetMethodSignature(const dex::MethodId& method_id) const {
135   return Signature(this, GetProtoId(method_id.proto_idx_));
136 }
137 
GetProtoSignature(const dex::ProtoId & proto_id)138 inline const Signature DexFile::GetProtoSignature(const dex::ProtoId& proto_id) const {
139   return Signature(this, proto_id);
140 }
141 
GetMethodName(const dex::MethodId & method_id)142 inline const char* DexFile::GetMethodName(const dex::MethodId& method_id) const {
143   return StringDataByIdx(method_id.name_idx_);
144 }
145 
GetMethodName(const dex::MethodId & method_id,uint32_t * utf_length)146 inline const char* DexFile::GetMethodName(const dex::MethodId& method_id, uint32_t* utf_length)
147     const {
148   return StringDataAndUtf16LengthByIdx(method_id.name_idx_, utf_length);
149 }
150 
GetMethodName(uint32_t idx)151 inline const char* DexFile::GetMethodName(uint32_t idx) const {
152   return StringDataByIdx(GetMethodId(idx).name_idx_);
153 }
154 
GetMethodName(uint32_t idx,uint32_t * utf_length)155 inline const char* DexFile::GetMethodName(uint32_t idx, uint32_t* utf_length) const {
156   return StringDataAndUtf16LengthByIdx(GetMethodId(idx).name_idx_, utf_length);
157 }
158 
159 ALWAYS_INLINE
GetMethodNameView(const dex::MethodId & method_id)160 inline std::string_view DexFile::GetMethodNameView(const dex::MethodId& method_id) const {
161   return StringViewByIdx(method_id.name_idx_);
162 }
163 
164 ALWAYS_INLINE
GetMethodNameView(uint32_t idx)165 inline std::string_view DexFile::GetMethodNameView(uint32_t idx) const {
166   return GetMethodNameView(GetMethodId(idx));
167 }
168 
GetMethodShorty(uint32_t idx)169 inline const char* DexFile::GetMethodShorty(uint32_t idx) const {
170   return StringDataByIdx(GetProtoId(GetMethodId(idx).proto_idx_).shorty_idx_);
171 }
172 
GetMethodShorty(const dex::MethodId & method_id)173 inline const char* DexFile::GetMethodShorty(const dex::MethodId& method_id) const {
174   return StringDataByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_);
175 }
176 
GetMethodShorty(const dex::MethodId & method_id,uint32_t * length)177 inline const char* DexFile::GetMethodShorty(const dex::MethodId& method_id, uint32_t* length)
178     const {
179   // Using the UTF16 length is safe here as shorties are guaranteed to be ASCII characters.
180   return StringDataAndUtf16LengthByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_, length);
181 }
182 
GetClassDescriptor(const dex::ClassDef & class_def)183 inline const char* DexFile::GetClassDescriptor(const dex::ClassDef& class_def) const {
184   return StringByTypeIdx(class_def.class_idx_);
185 }
186 
GetReturnTypeDescriptor(const dex::ProtoId & proto_id)187 inline const char* DexFile::GetReturnTypeDescriptor(const dex::ProtoId& proto_id) const {
188   return StringByTypeIdx(proto_id.return_type_idx_);
189 }
190 
GetShorty(dex::ProtoIndex proto_idx)191 inline const char* DexFile::GetShorty(dex::ProtoIndex proto_idx) const {
192   const dex::ProtoId& proto_id = GetProtoId(proto_idx);
193   return StringDataByIdx(proto_id.shorty_idx_);
194 }
195 
196 ALWAYS_INLINE
GetShortyView(const dex::ProtoId & proto_id)197 inline std::string_view DexFile::GetShortyView(const dex::ProtoId& proto_id) const {
198   uint32_t lhs_shorty_len;
199   const char* lhs_shorty_data =
200       StringDataAndUtf16LengthByIdx(proto_id.shorty_idx_, &lhs_shorty_len);
201   DCHECK_EQ(lhs_shorty_data[lhs_shorty_len], '\0');  // For a shorty utf16 length == mutf8 length.
202   return std::string_view(lhs_shorty_data, lhs_shorty_len);
203 }
204 
GetTryItems(const DexInstructionIterator & code_item_end,uint32_t offset)205 inline const dex::TryItem* DexFile::GetTryItems(const DexInstructionIterator& code_item_end,
206                                                 uint32_t offset) {
207   return reinterpret_cast<const dex::TryItem*>
208       (RoundUp(reinterpret_cast<uintptr_t>(&code_item_end.Inst()), dex::TryItem::kAlignment)) +
209           offset;
210 }
211 
StringEquals(const DexFile * df1,dex::StringIndex sidx1,const DexFile * df2,dex::StringIndex sidx2)212 inline bool DexFile::StringEquals(const DexFile* df1, dex::StringIndex sidx1,
213                                   const DexFile* df2, dex::StringIndex sidx2) {
214   uint32_t s1_len;  // Note: utf16 length != mutf8 length.
215   const char* s1_data = df1->StringDataAndUtf16LengthByIdx(sidx1, &s1_len);
216   uint32_t s2_len;
217   const char* s2_data = df2->StringDataAndUtf16LengthByIdx(sidx2, &s2_len);
218   return (s1_len == s2_len) && (strcmp(s1_data, s2_data) == 0);
219 }
220 
221 template<typename NewLocalCallback, typename IndexToStringData, typename TypeIndexToStringData>
DecodeDebugLocalInfo(const uint8_t * stream,const std::string & location,const char * declaring_class_descriptor,const std::vector<const char * > & arg_descriptors,const std::string & method_name,bool is_static,uint16_t registers_size,uint16_t ins_size,uint16_t insns_size_in_code_units,const IndexToStringData & index_to_string_data,const TypeIndexToStringData & type_index_to_string_data,const NewLocalCallback & new_local_callback)222 bool DexFile::DecodeDebugLocalInfo(const uint8_t* stream,
223                                    const std::string& location,
224                                    const char* declaring_class_descriptor,
225                                    const std::vector<const char*>& arg_descriptors,
226                                    const std::string& method_name,
227                                    bool is_static,
228                                    uint16_t registers_size,
229                                    uint16_t ins_size,
230                                    uint16_t insns_size_in_code_units,
231                                    const IndexToStringData& index_to_string_data,
232                                    const TypeIndexToStringData& type_index_to_string_data,
233                                    const NewLocalCallback& new_local_callback) {
234   if (stream == nullptr) {
235     return false;
236   }
237   std::vector<LocalInfo> local_in_reg(registers_size);
238 
239   uint16_t arg_reg = registers_size - ins_size;
240   if (!is_static) {
241     const char* descriptor = declaring_class_descriptor;
242     local_in_reg[arg_reg].name_ = "this";
243     local_in_reg[arg_reg].descriptor_ = descriptor;
244     local_in_reg[arg_reg].signature_ = nullptr;
245     local_in_reg[arg_reg].start_address_ = 0;
246     local_in_reg[arg_reg].reg_ = arg_reg;
247     local_in_reg[arg_reg].is_live_ = true;
248     arg_reg++;
249   }
250 
251   DecodeUnsignedLeb128(&stream);  // Line.
252   uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
253   uint32_t i;
254   if (parameters_size != arg_descriptors.size()) {
255     LOG(ERROR) << "invalid stream - problem with parameter iterator in " << location
256                << " for method " << method_name;
257     return false;
258   }
259   for (i = 0; i < parameters_size && i < arg_descriptors.size(); ++i) {
260     if (arg_reg >= registers_size) {
261       LOG(ERROR) << "invalid stream - arg reg >= reg size (" << arg_reg
262                  << " >= " << registers_size << ") in " << location;
263       return false;
264     }
265     uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
266     const char* descriptor = arg_descriptors[i];
267     local_in_reg[arg_reg].name_ = index_to_string_data(name_idx);
268     local_in_reg[arg_reg].descriptor_ = descriptor;
269     local_in_reg[arg_reg].signature_ = nullptr;
270     local_in_reg[arg_reg].start_address_ = 0;
271     local_in_reg[arg_reg].reg_ = arg_reg;
272     local_in_reg[arg_reg].is_live_ = true;
273     switch (*descriptor) {
274       case 'D':
275       case 'J':
276         arg_reg += 2;
277         break;
278       default:
279         arg_reg += 1;
280         break;
281     }
282   }
283 
284   uint32_t address = 0;
285   for (;;)  {
286     uint8_t opcode = *stream++;
287     switch (opcode) {
288       case DBG_END_SEQUENCE:
289         // Emit all variables which are still alive at the end of the method.
290         for (uint16_t reg = 0; reg < registers_size; reg++) {
291           if (local_in_reg[reg].is_live_) {
292             local_in_reg[reg].end_address_ = insns_size_in_code_units;
293             new_local_callback(local_in_reg[reg]);
294           }
295         }
296         return true;
297       case DBG_ADVANCE_PC:
298         address += DecodeUnsignedLeb128(&stream);
299         break;
300       case DBG_ADVANCE_LINE:
301         DecodeSignedLeb128(&stream);  // Line.
302         break;
303       case DBG_START_LOCAL:
304       case DBG_START_LOCAL_EXTENDED: {
305         uint16_t reg = DecodeUnsignedLeb128(&stream);
306         if (reg >= registers_size) {
307           LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
308                      << registers_size << ") in " << location;
309           return false;
310         }
311 
312         uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
313         uint16_t descriptor_idx = DecodeUnsignedLeb128P1(&stream);
314         uint32_t signature_idx = dex::kDexNoIndex;
315         if (opcode == DBG_START_LOCAL_EXTENDED) {
316           signature_idx = DecodeUnsignedLeb128P1(&stream);
317         }
318 
319         // Emit what was previously there, if anything
320         if (local_in_reg[reg].is_live_) {
321           local_in_reg[reg].end_address_ = address;
322           new_local_callback(local_in_reg[reg]);
323         }
324 
325         local_in_reg[reg].name_ = index_to_string_data(name_idx);
326         local_in_reg[reg].descriptor_ = type_index_to_string_data(descriptor_idx);;
327         local_in_reg[reg].signature_ = index_to_string_data(signature_idx);
328         local_in_reg[reg].start_address_ = address;
329         local_in_reg[reg].reg_ = reg;
330         local_in_reg[reg].is_live_ = true;
331         break;
332       }
333       case DBG_END_LOCAL: {
334         uint16_t reg = DecodeUnsignedLeb128(&stream);
335         if (reg >= registers_size) {
336           LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
337                      << registers_size << ") in " << location;
338           return false;
339         }
340         // If the register is live, close it properly. Otherwise, closing an already
341         // closed register is sloppy, but harmless if no further action is taken.
342         if (local_in_reg[reg].is_live_) {
343           local_in_reg[reg].end_address_ = address;
344           new_local_callback(local_in_reg[reg]);
345           local_in_reg[reg].is_live_ = false;
346         }
347         break;
348       }
349       case DBG_RESTART_LOCAL: {
350         uint16_t reg = DecodeUnsignedLeb128(&stream);
351         if (reg >= registers_size) {
352           LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
353                      << registers_size << ") in " << location;
354           return false;
355         }
356         // If the register is live, the "restart" is superfluous,
357         // and we don't want to mess with the existing start address.
358         if (!local_in_reg[reg].is_live_) {
359           local_in_reg[reg].start_address_ = address;
360           local_in_reg[reg].is_live_ = true;
361         }
362         break;
363       }
364       case DBG_SET_PROLOGUE_END:
365       case DBG_SET_EPILOGUE_BEGIN:
366         break;
367       case DBG_SET_FILE:
368         DecodeUnsignedLeb128P1(&stream);  // name.
369         break;
370       default:
371         address += (opcode - DBG_FIRST_SPECIAL) / DBG_LINE_RANGE;
372         break;
373     }
374   }
375 }
376 
377 template<typename NewLocalCallback>
DecodeDebugLocalInfo(uint32_t registers_size,uint32_t ins_size,uint32_t insns_size_in_code_units,uint32_t debug_info_offset,bool is_static,uint32_t method_idx,const NewLocalCallback & new_local_callback)378 bool DexFile::DecodeDebugLocalInfo(uint32_t registers_size,
379                                    uint32_t ins_size,
380                                    uint32_t insns_size_in_code_units,
381                                    uint32_t debug_info_offset,
382                                    bool is_static,
383                                    uint32_t method_idx,
384                                    const NewLocalCallback& new_local_callback) const {
385   const uint8_t* const stream = GetDebugInfoStream(debug_info_offset);
386   if (stream == nullptr) {
387     return false;
388   }
389   std::vector<const char*> arg_descriptors;
390   DexFileParameterIterator it(*this, GetMethodPrototype(GetMethodId(method_idx)));
391   for (; it.HasNext(); it.Next()) {
392     arg_descriptors.push_back(it.GetDescriptor());
393   }
394   return DecodeDebugLocalInfo(stream,
395                               GetLocation(),
396                               GetMethodDeclaringClassDescriptor(GetMethodId(method_idx)),
397                               arg_descriptors,
398                               this->PrettyMethod(method_idx),
399                               is_static,
400                               registers_size,
401                               ins_size,
402                               insns_size_in_code_units,
403                               [this](uint32_t idx) {
404                                 return StringDataByIdx(dex::StringIndex(idx));
405                               },
406                               [this](uint32_t idx) {
407                                 return StringByTypeIdx(dex::TypeIndex(
408                                     dchecked_integral_cast<uint16_t>(idx)));
409                               },
410                               new_local_callback);
411 }
412 
413 template<typename DexDebugNewPosition, typename IndexToStringData>
DecodeDebugPositionInfo(const uint8_t * stream,const IndexToStringData & index_to_string_data,const DexDebugNewPosition & position_functor)414 bool DexFile::DecodeDebugPositionInfo(const uint8_t* stream,
415                                       const IndexToStringData& index_to_string_data,
416                                       const DexDebugNewPosition& position_functor) {
417   if (stream == nullptr) {
418     return false;
419   }
420 
421   PositionInfo entry;
422   entry.line_ = DecodeDebugInfoParameterNames(&stream, VoidFunctor());
423 
424   for (;;)  {
425     uint8_t opcode = *stream++;
426     switch (opcode) {
427       case DBG_END_SEQUENCE:
428         return true;  // end of stream.
429       case DBG_ADVANCE_PC:
430         entry.address_ += DecodeUnsignedLeb128(&stream);
431         break;
432       case DBG_ADVANCE_LINE:
433         entry.line_ += DecodeSignedLeb128(&stream);
434         break;
435       case DBG_START_LOCAL:
436         DecodeUnsignedLeb128(&stream);  // reg.
437         DecodeUnsignedLeb128P1(&stream);  // name.
438         DecodeUnsignedLeb128P1(&stream);  // descriptor.
439         break;
440       case DBG_START_LOCAL_EXTENDED:
441         DecodeUnsignedLeb128(&stream);  // reg.
442         DecodeUnsignedLeb128P1(&stream);  // name.
443         DecodeUnsignedLeb128P1(&stream);  // descriptor.
444         DecodeUnsignedLeb128P1(&stream);  // signature.
445         break;
446       case DBG_END_LOCAL:
447       case DBG_RESTART_LOCAL:
448         DecodeUnsignedLeb128(&stream);  // reg.
449         break;
450       case DBG_SET_PROLOGUE_END:
451         entry.prologue_end_ = true;
452         break;
453       case DBG_SET_EPILOGUE_BEGIN:
454         entry.epilogue_begin_ = true;
455         break;
456       case DBG_SET_FILE: {
457         uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
458         entry.source_file_ = index_to_string_data(name_idx);
459         break;
460       }
461       default: {
462         int adjopcode = opcode - DBG_FIRST_SPECIAL;
463         entry.address_ += adjopcode / DBG_LINE_RANGE;
464         entry.line_ += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
465         if (position_functor(entry)) {
466           return true;  // early exit.
467         }
468         entry.prologue_end_ = false;
469         entry.epilogue_begin_ = false;
470         break;
471       }
472     }
473   }
474 }
475 
AsCompactDexFile()476 inline const CompactDexFile* DexFile::AsCompactDexFile() const {
477   DCHECK(IsCompactDexFile());
478   return down_cast<const CompactDexFile*>(this);
479 }
480 
AsStandardDexFile()481 inline const StandardDexFile* DexFile::AsStandardDexFile() const {
482   DCHECK(IsStandardDexFile());
483   return down_cast<const StandardDexFile*>(this);
484 }
485 
486 // Get the base of the encoded data for the given DexCode.
GetCatchHandlerData(const DexInstructionIterator & code_item_end,uint32_t tries_size,uint32_t offset)487 inline const uint8_t* DexFile::GetCatchHandlerData(const DexInstructionIterator& code_item_end,
488                                                    uint32_t tries_size,
489                                                    uint32_t offset) {
490   const uint8_t* handler_data =
491       reinterpret_cast<const uint8_t*>(GetTryItems(code_item_end, tries_size));
492   return handler_data + offset;
493 }
494 
GetClasses()495 inline IterationRange<ClassIterator> DexFile::GetClasses() const {
496   return { ClassIterator(*this, 0u), ClassIterator(*this, NumClassDefs()) };
497 }
498 
499 // Returns the line number
500 template <typename Visitor>
DecodeDebugInfoParameterNames(const uint8_t ** debug_info,const Visitor & visitor)501 inline uint32_t DexFile::DecodeDebugInfoParameterNames(const uint8_t** debug_info,
502                                                        const Visitor& visitor) {
503   uint32_t line = DecodeUnsignedLeb128(debug_info);
504   const uint32_t parameters_size = DecodeUnsignedLeb128(debug_info);
505   for (uint32_t i = 0; i < parameters_size; ++i) {
506     visitor(dex::StringIndex(DecodeUnsignedLeb128P1(debug_info)));
507   }
508   return line;
509 }
510 
511 }  // namespace art
512 
513 #endif  // ART_LIBDEXFILE_DEX_DEX_FILE_INL_H_
514