Skip to content

Commit 7b85cc4

Browse files
committed
[lldb/crashlog] Enforce image loading policy
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 5445a35 commit 7b85cc4

File tree

2 files changed

+61
-57
lines changed

2 files changed

+61
-57
lines changed

lldb/examples/python/crashlog.py

Lines changed: 48 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,47 @@ def create_target(self):
526526
def get_target(self):
527527
return self.target
528528

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

530571
class CrashLogFormatException(Exception):
531572
pass
@@ -1408,36 +1449,7 @@ def SymbolicateCrashLog(crash_log, options):
14081449
if not target:
14091450
return
14101451

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)
1452+
crash_log.load_images(options)
14411453

14421454
if crash_log.backtraces:
14431455
for thread in crash_log.backtraces:
@@ -1498,7 +1510,11 @@ def load_crashlog_in_scripted_process(debugger, crashlog_path, options, result):
14981510
structured_data = lldb.SBStructuredData()
14991511
structured_data.SetFromJSON(
15001512
json.dumps(
1501-
{"file_path": crashlog_path, "load_all_images": options.load_all_images}
1513+
{
1514+
"file_path": crashlog_path,
1515+
"load_all_images": options.load_all_images,
1516+
"crashed_only": options.crashed_only,
1517+
}
15021518
)
15031519
)
15041520
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)