Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
Fix the stack decoder.
Browse files Browse the repository at this point in the history
Trying to decode a stack with a dex pc frame which comes from an
apk, the script throws a number of errors. Fix those errors.

Bug: 356896129

Test: Ran a backtrace with an apk and verified it properly shows the right
Test: file and doesn't emit any crashes.
Change-Id: I883e72e71d97b44c57d82664e6198d40164478a0
  • Loading branch information
cferris1000 committed Jan 22, 2025
1 parent 5aaffb2 commit a0822a7
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 21 deletions.
31 changes: 20 additions & 11 deletions scripts/stack_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,12 @@ def ProcessCentralInfo(self, offset_list, central_info):
name = match.group(1)
start = int(match.group(2))
end = start + int(match.group(3))
# When the actual apk data is mapped in to the process, it will be
# mapped in on a page boundary. This means the header data can start
# after the actual offset and the code will get the wrong file.
# Rounding down to a page boundary (assumes 4096 page size) fixes
# this problem.
start = start & ~0xfff

offset_list.append([name, start, end])
return name, start, end
Expand Down Expand Up @@ -553,6 +559,7 @@ def ProcessLine(self, line):
# Some.apk!libshared.so
# or
# Some.apk
lib_extracted = False
if so_offset:
# If it ends in apk, we are done.
apk = None
Expand All @@ -572,6 +579,7 @@ def ProcessLine(self, line):
apk = area[0:index + 4]
if apk:
lib_name, lib = self.GetLibFromApk(apk, so_offset)
lib_extracted = lib != None
else:
# Sometimes we'll see something like:
# #01 pc abcd libart.so!libart.so
Expand All @@ -583,17 +591,18 @@ def ProcessLine(self, line):
lib = area
lib_name = None

if build_id:
# If we have the build_id, do a brute-force search of the symbols directory.
basename = os.path.basename(lib).split("!")[-1]
lib = self.GetLibraryByBuildId(symbol.SYMBOLS_DIR, basename, build_id)
if not lib:
print("WARNING: Cannot find {} with build id {} in symbols directory."
.format(basename, build_id))
else:
# When using atest, test paths are different between the out/ directory
# and device. Apply fixups.
lib = self.GetLibPath(lib)
if not lib_extracted:
if build_id:
# If we have the build_id, do a brute-force search of the symbols directory.
basename = os.path.basename(lib).split("!")[-1]
lib = self.GetLibraryByBuildId(symbol.SYMBOLS_DIR, basename, build_id)
if not lib:
print("WARNING: Cannot find {} with build id {} in symbols directory."
.format(basename, build_id))
else:
# When using atest, test paths are different between the out/ directory
# and device. Apply fixups.
lib = self.GetLibPath(lib)

# If a calls b which further calls c and c is inlined to b, we want to
# display "a -> b -> c" in the stack trace instead of just "a -> c"
Expand Down
23 changes: 13 additions & 10 deletions scripts/symbol.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,14 @@ def GetProcess(self, cmd):
return pipe

def SpawnProcess(self, cmd):
return subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
return subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)

def TerminateProcess(self, pipe):
pipe.stdin.close()
pipe.stdout.close()
pipe.terminate()
if pipe.poll() is None:
# Process is still running.
pipe.stdin.close()
pipe.stdout.close()
pipe.terminate()
pipe.wait()

def KillAllProcesses(self):
Expand Down Expand Up @@ -304,7 +306,7 @@ def GetStackRecordsForSet(lib, unique_addrs):
frame_offset, size, tag_offset may be None.
"""
child = _GetJSONSymbolizerForLib(lib)
if child is None:
if child is None or child.poll() is not None:
return None
records = []
for addr in unique_addrs:
Expand Down Expand Up @@ -374,11 +376,12 @@ def CallLlvmSymbolizerForSet(lib, unique_addrs):
child.stdin.flush()
records = []
json_result = json.loads(child.stdout.readline().strip())
for symbol in json_result["Symbol"]:
function_name = symbol["FunctionName"]
# GNU style location: file_name:line_num
location = ("%s:%s" % (symbol["FileName"], symbol["Line"]))
records.append((function_name, location))
if "Symbol" in json_result:
for symbol in json_result["Symbol"]:
function_name = symbol["FunctionName"]
# GNU style location: file_name:line_num
location = ("%s:%s" % (symbol["FileName"], symbol["Line"]))
records.append((function_name, location))
except IOError as e:
# Remove the / in front of the library name to match other output.
records = [(None, lib[1:] + " ***Error: " + str(e))]
Expand Down

0 comments on commit a0822a7

Please sign in to comment.