[lldb/crashlog] Create interactive crashlog with no binary

This patch changes the way we load a crash report into a scripted
process by creating a empty target.

To do so, it parses the architecture information from the report (for
both the legacy and json format) and uses that to create a target that
doesn't have any executable, like what we do when attaching to a process.

For the legacy format, we mostly rely on the `Code Type` line, since the
architure is an optional field on the `Binary Images` sections.

However for the json format, we first try to get the architecture while
parsing the image dictionary if we couldn't find it, we try to infer it
using the "flavor" key when parsing the frame's registers.

If the architecture is still not set after parsing the report, we raise
an exception.

rdar://107850263

Differential Revision: https://reviews.llvm.org/D151849

Differential

Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
This commit is contained in:
Med Ismail Bennani
2023-06-01 17:10:39 -07:00
parent a5a6c03c44
commit 032d91cb2f
2 changed files with 32 additions and 5 deletions

View File

@@ -395,6 +395,10 @@ class CrashLog(symbolication.Symbolicator):
self.version = -1
self.target = None
self.verbose = verbose
self.process_id = None
self.process_identifier = None
self.process_path = None
self.process_arch = None
def dump(self):
print("Crash Log File: %s" % (self.path))
@@ -484,9 +488,9 @@ class CrashLogParser:
def __init__(self, debugger, path, verbose):
self.path = os.path.expanduser(path)
self.verbose = verbose
self.crashlog = CrashLog(debugger, self.path, self.verbose)
# List of DarwinImages sorted by their index.
self.images = list()
self.crashlog = CrashLog(debugger, self.path, self.verbose)
@abc.abstractmethod
def parse(self):
@@ -547,6 +551,8 @@ class JSONCrashLogParser(CrashLogParser):
def parse_process_info(self, json_data):
self.crashlog.process_id = json_data["pid"]
self.crashlog.process_identifier = json_data["procName"]
if "procPath" in json_data:
self.crashlog.process_path = json_data["procPath"]
def parse_crash_reason(self, json_exception):
self.crashlog.exception = json_exception
@@ -574,6 +580,10 @@ class JSONCrashLogParser(CrashLogParser):
darwin_image = self.crashlog.DarwinImage(
low, high, name, version, img_uuid, path, self.verbose
)
if "arch" in json_image:
darwin_image.arch = json_image["arch"]
if path == self.crashlog.process_path:
self.crashlog.process_arch = darwin_image.arch
self.images.append(darwin_image)
self.crashlog.images.append(darwin_image)
@@ -740,6 +750,13 @@ class JSONCrashLogParser(CrashLogParser):
gpr_dict = {str(idx): reg for idx, reg in enumerate(state)}
registers.update(self.parse_thread_registers(gpr_dict, key))
continue
if key == "flavor":
if not self.crashlog.process_arch:
if state == "ARM_THREAD_STATE64":
self.crashlog.process_arch = "arm64"
elif state == "X86_THREAD_STATE":
self.crashlog.process_arch = "x86_64"
continue
try:
value = int(state["value"])
registers["{}{}".format(prefix or "", key)] = value
@@ -912,6 +929,8 @@ class TextCrashLogParser(CrashLogParser):
line[8:].strip().split(" [")
)
self.crashlog.process_id = pid_with_brackets.strip("[]")
elif line.startswith("Path:"):
self.crashlog.process_path = line[5:].strip()
elif line.startswith("Identifier:"):
self.crashlog.process_identifier = line[11:].strip()
elif line.startswith("Version:"):
@@ -923,6 +942,11 @@ class TextCrashLogParser(CrashLogParser):
else:
self.crashlog.process = version_string
self.crashlog.process_compatability_version = version_string
elif line.startswith("Code Type:"):
if "ARM-64" in line:
self.crashlog.process_arch = "arm64"
elif "X86-64" in line:
self.crashlog.process_arch = "x86_64"
elif self.parent_process_regex.search(line):
parent_process_match = self.parent_process_regex.search(line)
self.crashlog.parent_process_name = parent_process_match.group(1)
@@ -1343,9 +1367,12 @@ def load_crashlog_in_scripted_process(debugger, crash_log_file, options, result)
# 2. If the user didn't provide a target, try to create a target using the symbolicator
if not target or not target.IsValid():
target = crashlog.create_target()
# 3. If that didn't work, and a target is already loaded, use it
if (target is None or not target.IsValid()) and debugger.GetNumTargets() > 0:
target = debugger.GetTargetAtIndex(0)
# 3. If that didn't work, create a dummy target
if target is None or not target.IsValid():
arch = crashlog.process_arch
if not arch:
raise InteractiveCrashLogException("couldn't create find the architecture to create the target")
target = debugger.CreateTargetWithFileAndArch(None, arch)
# 4. Fail
if target is None or not target.IsValid():
raise InteractiveCrashLogException("couldn't create target")