Skip to content

Commit 785b143

Browse files
authored
[lldb/crashlog] Enforce image loading policy (llvm#91109)
In `27f27d1`, we changed the image loading logic to conform to the various options (`-a|--load-all` & `-c|--crashed-only`) and loaded them concurrently. However, instead of the subset of images that matched the user option, the thread pool would always run on all the crashlog images, causing them to be all loaded in the target everytime. This matches the `-a|--load-all` option behaviour but depending on the report, it can cause lldb to load thousands of images, which can take a very long time if the images are downloaded over the network. This patch fixes that issue by keeping a list of `images_to_load` based of the user-provided option. This list will be used with our executor thread pool to load the images according to the user selection, and reinstates the expected default behaviour, by only loading the crashed thread images and skipping all the others. This patch also unifies the way we load images into a single method that's shared by both the batch mode & the interactive scripted process. rdar://123694062 Signed-off-by: Med Ismail Bennani <[email protected]>
1 parent ecae3ed commit 785b143

File tree

2 files changed

+63
-57
lines changed

2 files changed

+63
-57
lines changed

lldb/examples/python/crashlog.py

Lines changed: 50 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ def add_ident(self, ident):
252252
self.idents.append(ident)
253253

254254
def did_crash(self):
255-
return self.reason is not None
255+
return self.crashed
256256

257257
def __str__(self):
258258
if self.app_specific_backtrace:
@@ -526,6 +526,49 @@ def create_target(self):
526526
def get_target(self):
527527
return self.target
528528

529+
def load_images(self, options, loaded_images=None):
530+
if not loaded_images:
531+
loaded_images = []
532+
images_to_load = self.images
533+
if options.load_all_images:
534+
for image in self.images:
535+
image.resolve = True
536+
elif options.crashed_only:
537+
for thread in self.threads:
538+
if thread.did_crash():
539+
images_to_load = []
540+
for ident in thread.idents:
541+
for image in self.find_images_with_identifier(ident):
542+
image.resolve = True
543+
images_to_load.append(image)
544+
545+
futures = []
546+
with tempfile.TemporaryDirectory() as obj_dir:
547+
with concurrent.futures.ThreadPoolExecutor() as executor:
548+
549+
def add_module(image, target, obj_dir):
550+
return image, image.add_module(target, obj_dir)
551+
552+
for image in images_to_load:
553+
if image not in loaded_images:
554+
if image.uuid == uuid.UUID(int=0):
555+
continue
556+
futures.append(
557+
executor.submit(
558+
add_module,
559+
image=image,
560+
target=self.target,
561+
obj_dir=obj_dir,
562+
)
563+
)
564+
565+
for future in concurrent.futures.as_completed(futures):
566+
image, err = future.result()
567+
if err:
568+
print(err)
569+
else:
570+
loaded_images.append(image)
571+
529572

530573
class CrashLogFormatException(Exception):
531574
pass
@@ -1408,36 +1451,7 @@ def SymbolicateCrashLog(crash_log, options):
14081451
if not target:
14091452
return
14101453

1411-
if options.load_all_images:
1412-
for image in crash_log.images:
1413-
image.resolve = True
1414-
elif options.crashed_only:
1415-
for thread in crash_log.threads:
1416-
if thread.did_crash():
1417-
for ident in thread.idents:
1418-
for image in crash_log.find_images_with_identifier(ident):
1419-
image.resolve = True
1420-
1421-
futures = []
1422-
loaded_images = []
1423-
with tempfile.TemporaryDirectory() as obj_dir:
1424-
with concurrent.futures.ThreadPoolExecutor() as executor:
1425-
1426-
def add_module(image, target, obj_dir):
1427-
return image, image.add_module(target, obj_dir)
1428-
1429-
for image in crash_log.images:
1430-
futures.append(
1431-
executor.submit(
1432-
add_module, image=image, target=target, obj_dir=obj_dir
1433-
)
1434-
)
1435-
for future in concurrent.futures.as_completed(futures):
1436-
image, err = future.result()
1437-
if err:
1438-
print(err)
1439-
else:
1440-
loaded_images.append(image)
1454+
crash_log.load_images(options)
14411455

14421456
if crash_log.backtraces:
14431457
for thread in crash_log.backtraces:
@@ -1498,7 +1512,11 @@ def load_crashlog_in_scripted_process(debugger, crashlog_path, options, result):
14981512
structured_data = lldb.SBStructuredData()
14991513
structured_data.SetFromJSON(
15001514
json.dumps(
1501-
{"file_path": crashlog_path, "load_all_images": options.load_all_images}
1515+
{
1516+
"file_path": crashlog_path,
1517+
"load_all_images": options.load_all_images,
1518+
"crashed_only": options.crashed_only,
1519+
}
15021520
)
15031521
)
15041522
launch_info = lldb.SBLaunchInfo(None)

lldb/examples/python/crashlog_scripted_process.py

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,27 +29,7 @@ def set_crashlog(self, crashlog):
2929
if hasattr(self.crashlog, "asb"):
3030
self.extended_thread_info = self.crashlog.asb
3131

32-
if self.load_all_images:
33-
for image in self.crashlog.images:
34-
image.resolve = True
35-
else:
36-
for thread in self.crashlog.threads:
37-
if thread.did_crash():
38-
for ident in thread.idents:
39-
for image in self.crashlog.find_images_with_identifier(ident):
40-
image.resolve = True
41-
42-
with tempfile.TemporaryDirectory() as obj_dir:
43-
for image in self.crashlog.images:
44-
if image not in self.loaded_images:
45-
if image.uuid == uuid.UUID(int=0):
46-
continue
47-
err = image.add_module(self.target, obj_dir)
48-
if err:
49-
# Append to SBCommandReturnObject
50-
print(err)
51-
else:
52-
self.loaded_images.append(image)
32+
crashlog.load_images(self.options, self.loaded_images)
5333

5434
for thread in self.crashlog.threads:
5535
if (
@@ -70,6 +50,10 @@ def set_crashlog(self, crashlog):
7050
self.app_specific_thread, self.addr_mask, self.target
7151
)
7252

53+
class CrashLogOptions:
54+
load_all_images = False
55+
crashed_only = True
56+
7357
def __init__(self, exe_ctx: lldb.SBExecutionContext, args: lldb.SBStructuredData):
7458
super().__init__(exe_ctx, args)
7559

@@ -88,13 +72,17 @@ def __init__(self, exe_ctx: lldb.SBExecutionContext, args: lldb.SBStructuredData
8872
# Return error
8973
return
9074

75+
self.options = self.CrashLogOptions()
76+
9177
load_all_images = args.GetValueForKey("load_all_images")
9278
if load_all_images and load_all_images.IsValid():
9379
if load_all_images.GetType() == lldb.eStructuredDataTypeBoolean:
94-
self.load_all_images = load_all_images.GetBooleanValue()
80+
self.options.load_all_images = load_all_images.GetBooleanValue()
9581

96-
if not self.load_all_images:
97-
self.load_all_images = False
82+
crashed_only = args.GetValueForKey("crashed_only")
83+
if crashed_only and crashed_only.IsValid():
84+
if crashed_only.GetType() == lldb.eStructuredDataTypeBoolean:
85+
self.options.crashed_only = crashed_only.GetBooleanValue()
9886

9987
self.pid = super().get_process_id()
10088
self.crashed_thread_idx = 0
@@ -159,7 +147,7 @@ def resolve_stackframes(thread, addr_mask, target):
159147
return frames
160148

161149
def create_stackframes(self):
162-
if not (self.originating_process.load_all_images or self.has_crashed):
150+
if not (self.originating_process.options.load_all_images or self.has_crashed):
163151
return None
164152

165153
if not self.backing_thread or not len(self.backing_thread.frames):

0 commit comments

Comments
 (0)