@@ -43,7 +43,10 @@ class TraceConverter:
43
43
sanitizer_trace_line = re .compile ("$a" )
44
44
value_line = re .compile ("$a" )
45
45
code_line = re .compile ("$a" )
46
- unzip_line = re .compile ("\s*(\d+)\s+\S+\s+\S+\s+(\S+)" )
46
+ zipinfo_central_directory_line = re .compile ("Central\s+directory\s+entry" )
47
+ zipinfo_central_info_match = re .compile (
48
+ "^\s*(\S+)$\s*offset of local header from start of archive:\s*(\d+)"
49
+ ".*^\s*compressed size:\s+(\d+)" , re .M | re .S )
47
50
trace_lines = []
48
51
value_lines = []
49
52
last_frame = - 1
@@ -163,10 +166,9 @@ def PrintDivider(self):
163
166
print "-----------------------------------------------------\n "
164
167
165
168
def DeleteApkTmpFiles (self ):
166
- for _ , offset_list in self .apk_info .values ():
167
- for _ , _ , tmp_file in offset_list :
168
- if tmp_file :
169
- os .unlink (tmp_file )
169
+ for _ , _ , tmp_files in self .apk_info .values ():
170
+ for tmp_file in tmp_files .values ():
171
+ os .unlink (tmp_file )
170
172
171
173
def ConvertTrace (self , lines ):
172
174
lines = map (self .CleanLine , lines )
@@ -216,20 +218,31 @@ def ExtractLibFromApk(self, apk, shared_lib_name):
216
218
os .unlink (tmp_file )
217
219
return None
218
220
221
+ def ProcessCentralInfo (self , offset_list , central_info ):
222
+ match = self .zipinfo_central_info_match .search (central_info )
223
+ if not match :
224
+ raise Exception ("Cannot find all info from zipinfo\n " + central_info )
225
+ name = match .group (1 )
226
+ start = int (match .group (2 ))
227
+ end = start + int (match .group (3 ))
228
+
229
+ offset_list .append ([name , start , end ])
230
+ return name , start , end
231
+
219
232
def GetLibFromApk (self , apk , offset ):
220
233
# Convert the string to hex.
221
234
offset = int (offset , 16 )
222
235
223
236
# Check if we already have information about this offset.
224
237
if apk in self .apk_info :
225
- apk_full_path , offset_list = self .apk_info [apk ]
226
- for current_offset , file_name , tmp_file in offset_list :
227
- if offset <= current_offset :
228
- if tmp_file :
229
- return file_name , tmp_file
230
- # This modifies the value in offset_list.
238
+ apk_full_path , offset_list , tmp_files = self .apk_info [apk ]
239
+ for file_name , start , end in offset_list :
240
+ if offset >= start and offset < end :
241
+ if file_name in tmp_files :
242
+ return file_name , tmp_files [file_name ]
231
243
tmp_file = self .ExtractLibFromApk (apk_full_path , file_name )
232
244
if tmp_file :
245
+ tmp_files [file_name ] = tmp_file
233
246
return file_name , tmp_file
234
247
break
235
248
return None , None
@@ -249,28 +262,38 @@ def GetLibFromApk(self, apk, offset):
249
262
print "Cannot find apk " + apk ;
250
263
return None , None
251
264
252
- cmd = subprocess .Popen (["unzip" , "-lqq" , apk_full_path ], stdout = subprocess .PIPE )
253
- current_offset = 0
254
- file_entry = None
265
+ cmd = subprocess .Popen (["zipinfo" , "-v" , apk_full_path ], stdout = subprocess .PIPE )
266
+ # Find the first central info marker.
267
+ for line in cmd .stdout :
268
+ if self .zipinfo_central_directory_line .search (line ):
269
+ break
270
+
271
+ central_info = ""
272
+ file_name = None
255
273
offset_list = []
256
274
for line in cmd .stdout :
257
- match = self .unzip_line . match (line )
275
+ match = self .zipinfo_central_directory_line . search (line )
258
276
if match :
259
- # Round the size up to a page boundary.
260
- current_offset += (int (match .group (1 ), 10 ) + 0x1000 ) & ~ 0xfff
261
- offset_entry = [current_offset - 1 , match .group (2 ), None ]
262
- offset_list .append (offset_entry )
263
- if offset < current_offset and not file_entry :
264
- file_entry = offset_entry
277
+ cur_name , start , end = self .ProcessCentralInfo (offset_list , central_info )
278
+ if not file_name and offset >= start and offset < end :
279
+ file_name = cur_name
280
+ central_info = ""
281
+ else :
282
+ central_info += line
283
+ if central_info :
284
+ cur_name , start , end = self .ProcessCentralInfo (offset_list , central_info )
285
+ if not file_name and offset >= start and offset < end :
286
+ file_name = cur_name
265
287
266
288
# Save the information from the zip.
267
- self .apk_info [apk ] = [apk_full_path , offset_list ]
268
- if not file_entry :
289
+ tmp_files = dict ()
290
+ self .apk_info [apk ] = [apk_full_path , offset_list , tmp_files ]
291
+ if not file_name :
269
292
return None , None
270
- tmp_shared_lib = self .ExtractLibFromApk (apk_full_path , file_entry [ 1 ] )
293
+ tmp_shared_lib = self .ExtractLibFromApk (apk_full_path , file_name )
271
294
if tmp_shared_lib :
272
- file_entry [ 2 ] = tmp_shared_lib
273
- return file_entry [ 1 ], file_entry [ 2 ]
295
+ tmp_files [ file_name ] = tmp_shared_lib
296
+ return file_name , tmp_shared_lib
274
297
return None , None
275
298
276
299
def ProcessLine (self , line ):
0 commit comments