Skip to content

Commit 8a5e377

Browse files
committed
[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 <[email protected]>
1 parent ef29265 commit 8a5e377

File tree

2 files changed

+32
-5
lines changed

2 files changed

+32
-5
lines changed

lldb/examples/python/crashlog.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,10 @@ def __init__(self, debugger, path, verbose):
409409
self.version = -1
410410
self.target = None
411411
self.verbose = verbose
412+
self.process_id = None
413+
self.process_identifier = None
414+
self.process_path = None
415+
self.process_arch = None
412416

413417
def dump(self):
414418
print("Crash Log File: %s" % (self.path))
@@ -498,9 +502,9 @@ def create(debugger, path, verbose):
498502
def __init__(self, debugger, path, verbose):
499503
self.path = os.path.expanduser(path)
500504
self.verbose = verbose
501-
self.crashlog = CrashLog(debugger, self.path, self.verbose)
502505
# List of DarwinImages sorted by their index.
503506
self.images = list()
507+
self.crashlog = CrashLog(debugger, self.path, self.verbose)
504508

505509
@abc.abstractmethod
506510
def parse(self):
@@ -561,6 +565,8 @@ def get_used_image(self, idx):
561565
def parse_process_info(self, json_data):
562566
self.crashlog.process_id = json_data["pid"]
563567
self.crashlog.process_identifier = json_data["procName"]
568+
if "procPath" in json_data:
569+
self.crashlog.process_path = json_data["procPath"]
564570

565571
def parse_crash_reason(self, json_exception):
566572
self.crashlog.exception = json_exception
@@ -588,6 +594,10 @@ def parse_images(self, json_images):
588594
darwin_image = self.crashlog.DarwinImage(
589595
low, high, name, version, img_uuid, path, self.verbose
590596
)
597+
if "arch" in json_image:
598+
darwin_image.arch = json_image["arch"]
599+
if path == self.crashlog.process_path:
600+
self.crashlog.process_arch = darwin_image.arch
591601
self.images.append(darwin_image)
592602
self.crashlog.images.append(darwin_image)
593603

@@ -730,6 +740,13 @@ def parse_thread_registers(self, json_thread_state, prefix=None):
730740
gpr_dict = {str(idx): reg for idx, reg in enumerate(state)}
731741
registers.update(self.parse_thread_registers(gpr_dict, key))
732742
continue
743+
if key == "flavor":
744+
if not self.crashlog.process_arch:
745+
if state == "ARM_THREAD_STATE64":
746+
self.crashlog.process_arch = "arm64"
747+
elif state == "X86_THREAD_STATE":
748+
self.crashlog.process_arch = "x86_64"
749+
continue
733750
try:
734751
value = int(state["value"])
735752
registers["{}{}".format(prefix or "", key)] = value
@@ -898,6 +915,8 @@ def parse_normal(self, line):
898915
line[8:].strip().split(" [")
899916
)
900917
self.crashlog.process_id = pid_with_brackets.strip("[]")
918+
elif line.startswith("Path:"):
919+
self.crashlog.process_path = line[5:].strip()
901920
elif line.startswith("Identifier:"):
902921
self.crashlog.process_identifier = line[11:].strip()
903922
elif line.startswith("Version:"):
@@ -909,6 +928,11 @@ def parse_normal(self, line):
909928
else:
910929
self.crashlog.process = version_string
911930
self.crashlog.process_compatability_version = version_string
931+
elif line.startswith("Code Type:"):
932+
if "ARM-64" in line:
933+
self.crashlog.process_arch = "arm64"
934+
elif "X86-64" in line:
935+
self.crashlog.process_arch = "x86_64"
912936
elif self.parent_process_regex.search(line):
913937
parent_process_match = self.parent_process_regex.search(line)
914938
self.crashlog.parent_process_name = parent_process_match.group(1)
@@ -1298,9 +1322,12 @@ def load_crashlog_in_scripted_process(debugger, crash_log_file, options, result)
12981322
# 2. If the user didn't provide a target, try to create a target using the symbolicator
12991323
if not target or not target.IsValid():
13001324
target = crashlog.create_target()
1301-
# 3. If that didn't work, and a target is already loaded, use it
1302-
if (target is None or not target.IsValid()) and debugger.GetNumTargets() > 0:
1303-
target = debugger.GetTargetAtIndex(0)
1325+
# 3. If that didn't work, create a dummy target
1326+
if target is None or not target.IsValid():
1327+
arch = crashlog.process_arch
1328+
if not arch:
1329+
raise InteractiveCrashLogException("couldn't create find the architecture to create the target")
1330+
target = debugger.CreateTargetWithFileAndArch(None, arch)
13041331
# 4. Fail
13051332
if target is None or not target.IsValid():
13061333
raise InteractiveCrashLogException("couldn't create target")

lldb/source/Target/Process.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2669,7 +2669,7 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state,
26692669

26702670
FileSpec exe_spec_to_use;
26712671
if (!exe_module) {
2672-
if (!launch_info.GetExecutableFile()) {
2672+
if (!launch_info.GetExecutableFile() && !launch_info.IsScriptedProcess()) {
26732673
error.SetErrorString("executable module does not exist");
26742674
return error;
26752675
}

0 commit comments

Comments
 (0)