Skip to content

Commit b189c45

Browse files
authored
Merge pull request #5562 from medismailben/stable/20220421
Cherry-pick many LLDB improvements
2 parents 58aa152 + 172f8d1 commit b189c45

34 files changed

+1126
-52
lines changed

lldb/examples/python/crashlog.py

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,12 @@ def parse(self):
462462
self.parse_images(self.data['usedImages'])
463463
self.parse_main_image(self.data)
464464
self.parse_threads(self.data['threads'])
465+
if 'asi' in self.data:
466+
self.crashlog.asi = self.data['asi']
467+
if 'asiBacktraces' in self.data:
468+
self.parse_app_specific_backtraces(self.data['asiBacktraces'])
469+
if 'lastExceptionBacktrace' in self.data:
470+
self.crashlog.asb = self.data['lastExceptionBacktrace']
465471
self.parse_errors(self.data)
466472
thread = self.crashlog.threads[self.crashlog.crashed_thread_idx]
467473
reason = self.parse_crash_reason(self.data['exception'])
@@ -573,6 +579,31 @@ def parse_threads(self, json_threads):
573579
self.crashlog.threads.append(thread)
574580
idx += 1
575581

582+
def parse_asi_backtrace(self, thread, bt):
583+
for line in bt.split('\n'):
584+
frame_match = TextCrashLogParser.frame_regex.search(line)
585+
if not frame_match:
586+
print("error: can't parse application specific backtrace.")
587+
return False
588+
589+
(frame_id, frame_img_name, frame_addr,
590+
frame_ofs) = frame_match.groups()
591+
592+
thread.add_ident(frame_img_name)
593+
if frame_img_name not in self.crashlog.idents:
594+
self.crashlog.idents.append(frame_img_name)
595+
thread.frames.append(self.crashlog.Frame(int(frame_id), int(
596+
frame_addr, 0), frame_ofs))
597+
598+
return True
599+
600+
def parse_app_specific_backtraces(self, json_app_specific_bts):
601+
for idx, backtrace in enumerate(json_app_specific_bts):
602+
thread = self.crashlog.Thread(idx, True)
603+
thread.queue = "Application Specific Backtrace"
604+
if self.parse_asi_backtrace(thread, backtrace):
605+
self.crashlog.threads.append(thread)
606+
576607
def parse_thread_registers(self, json_thread_state, prefix=None):
577608
registers = dict()
578609
for key, state in json_thread_state.items():
@@ -613,17 +644,17 @@ class TextCrashLogParser(CrashLogParser):
613644
frame_regex = re.compile(r'^(\d+)\s+' # id
614645
r'(.+?)\s+' # img_name
615646
r'(?:' +version+ r'\s+)?' # img_version
616-
r'(0x[0-9a-fA-F]{7,})' # addr (7 chars or more)
647+
r'(0x[0-9a-fA-F]{4,})' # addr (4 chars or more)
617648
r' +(.*)' # offs
618649
)
619-
null_frame_regex = re.compile(r'^\d+\s+\?\?\?\s+0{7,} +')
650+
null_frame_regex = re.compile(r'^\d+\s+\?\?\?\s+0{4,} +')
620651
image_regex_uuid = re.compile(r'(0x[0-9a-fA-F]+)' # img_lo
621652
r'\s+-\s+' # -
622653
r'(0x[0-9a-fA-F]+)\s+' # img_hi
623654
r'[+]?(.+?)\s+' # img_name
624655
r'(?:(' +version+ r')\s+)?' # img_version
625656
r'(?:<([-0-9a-fA-F]+)>\s+)?' # img_uuid
626-
r'(/.*)' # img_path
657+
r'(\?+|/.*)' # img_path
627658
)
628659
exception_type_regex = re.compile(r'^Exception Type:\s+(EXC_[A-Z_]+)(?:\s+\((.*)\))?')
629660
exception_codes_regex = re.compile(r'^Exception Codes:\s+(0x[0-9a-fA-F]+),\s*(0x[0-9a-fA-F]+)')
@@ -1102,8 +1133,8 @@ def synchronous(debugger):
11021133
run_options.SetEchoCommands(True)
11031134

11041135
commands_stream = lldb.SBStream()
1105-
commands_stream.Print("process status\n")
1106-
commands_stream.Print("thread backtrace\n")
1136+
commands_stream.Print("process status --verbose\n")
1137+
commands_stream.Print("thread backtrace --extended true\n")
11071138
error = debugger.SetInputString(commands_stream.GetData())
11081139
if error.Success():
11091140
debugger.RunCommandInterpreter(True, False, run_options, 0, False, True)

lldb/examples/python/scripted_process/crashlog_scripted_process.py

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ def parse_crashlog(self):
1818
self.crashed_thread_idx = crash_log.crashed_thread_idx
1919
self.loaded_images = []
2020
self.exception = crash_log.exception
21+
self.app_specific_thread = None
22+
if hasattr(crash_log, 'asi'):
23+
self.metadata['asi'] = crash_log.asi
24+
if hasattr(crash_log, 'asb'):
25+
self.extended_thread_info = crash_log.asb
2126

2227
def load_images(self, images):
2328
#TODO: Add to self.loaded_images and load images in lldb
@@ -40,8 +45,23 @@ def load_images(self, images):
4045
for ident in thread.idents:
4146
load_images(self, crash_log.find_images_with_identifier(ident))
4247

48+
if hasattr(thread, 'app_specific_backtrace') and thread.app_specific_backtrace:
49+
# We don't want to include the Application Specific Backtrace
50+
# Thread into the Scripted Process' Thread list.
51+
# Instead, we will try to extract the stackframe pcs from the
52+
# backtrace and inject that as the extended thread info.
53+
self.app_specific_thread = thread
54+
continue
55+
4356
self.threads[thread.index] = CrashLogScriptedThread(self, None, thread)
4457

58+
59+
if self.app_specific_thread:
60+
self.extended_thread_info = \
61+
CrashLogScriptedThread.resolve_stackframes(self.app_specific_thread,
62+
self.addr_mask,
63+
self.target)
64+
4565
def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
4666
super().__init__(target, args)
4767

@@ -71,6 +91,7 @@ def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
7191
self.pid = super().get_process_id()
7292
self.crashed_thread_idx = 0
7393
self.exception = None
94+
self.extended_thread_info = None
7495
self.parse_crashlog()
7596

7697
def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:
@@ -103,6 +124,9 @@ def is_alive(self) -> bool:
103124
def get_scripted_thread_plugin(self):
104125
return CrashLogScriptedThread.__module__ + "." + CrashLogScriptedThread.__name__
105126

127+
def get_process_metadata(self):
128+
return self.metadata
129+
106130
class CrashLogScriptedThread(ScriptedThread):
107131
def create_register_ctx(self):
108132
if not self.has_crashed:
@@ -120,21 +144,29 @@ def create_register_ctx(self):
120144

121145
return self.register_ctx
122146

147+
def resolve_stackframes(thread, addr_mask, target):
148+
frames = []
149+
for frame in thread.frames:
150+
frame_pc = frame.pc & addr_mask
151+
pc = frame_pc if frame.index == 0 or frame_pc == 0 else frame_pc - 1
152+
sym_addr = lldb.SBAddress()
153+
sym_addr.SetLoadAddress(pc, target)
154+
if not sym_addr.IsValid():
155+
continue
156+
frames.append({"idx": frame.index, "pc": pc})
157+
return frames
158+
159+
123160
def create_stackframes(self):
124161
if not (self.scripted_process.load_all_images or self.has_crashed):
125162
return None
126163

127164
if not self.backing_thread or not len(self.backing_thread.frames):
128165
return None
129166

130-
for frame in self.backing_thread.frames:
131-
frame_pc = frame.pc & self.scripted_process.addr_mask
132-
pc = frame_pc if frame.index == 0 or frame_pc == 0 else frame_pc - 1
133-
sym_addr = lldb.SBAddress()
134-
sym_addr.SetLoadAddress(pc, self.target)
135-
if not sym_addr.IsValid():
136-
continue
137-
self.frames.append({"idx": frame.index, "pc": pc})
167+
self.frames = CrashLogScriptedThread.resolve_stackframes(self.backing_thread,
168+
self.scripted_process.addr_mask,
169+
self.target)
138170

139171
return self.frames
140172

@@ -144,7 +176,10 @@ def __init__(self, process, args, crashlog_thread):
144176
self.backing_thread = crashlog_thread
145177
self.idx = self.backing_thread.index
146178
self.tid = self.backing_thread.id
147-
self.name = self.backing_thread.name
179+
if self.backing_thread.app_specific_backtrace:
180+
self.name = "Application Specific Backtrace - " + str(self.idx)
181+
else:
182+
self.name = self.backing_thread.name
148183
self.queue = self.backing_thread.queue
149184
self.has_crashed = (self.scripted_process.crashed_thread_idx == self.idx)
150185
self.create_stackframes()
@@ -168,3 +203,9 @@ def get_register_context(self) -> str:
168203
self.register_ctx = self.create_register_ctx()
169204

170205
return struct.pack("{}Q".format(len(self.register_ctx)), *self.register_ctx.values())
206+
207+
def get_extended_info(self):
208+
if (self.has_crashed):
209+
self.extended_info = self.scripted_process.extended_thread_info
210+
return self.extended_info
211+

lldb/examples/python/scripted_process/scripted_process.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class ScriptedProcess(metaclass=ABCMeta):
1818
stack_memory_dump = None
1919
loaded_images = None
2020
threads = None
21+
metadata = None
2122

2223
@abstractmethod
2324
def __init__(self, target, args):
@@ -41,6 +42,7 @@ def __init__(self, target, args):
4142
self.args = args
4243
self.threads = {}
4344
self.loaded_images = []
45+
self.metadata = {}
4446

4547
@abstractmethod
4648
def get_memory_region_containing_address(self, addr):
@@ -138,7 +140,6 @@ def get_process_id(self):
138140
"""
139141
return 0
140142

141-
142143
def launch(self):
143144
""" Simulate the scripted process launch.
144145
@@ -191,6 +192,15 @@ def get_scripted_thread_plugin(self):
191192
"""
192193
return None
193194

195+
def get_process_metadata(self):
196+
""" Get some metadata for the scripted process.
197+
198+
Returns:
199+
Dict: A dictionary containing metadata for the scripted process.
200+
None is the process as no metadata.
201+
"""
202+
return self.metadata
203+
194204
class ScriptedThread(metaclass=ABCMeta):
195205

196206
"""
@@ -226,6 +236,7 @@ def __init__(self, scripted_process, args):
226236
self.register_info = None
227237
self.register_ctx = {}
228238
self.frames = []
239+
self.extended_info = []
229240

230241
if isinstance(scripted_process, ScriptedProcess):
231242
self.target = scripted_process.target
@@ -334,6 +345,15 @@ def get_register_context(self):
334345
"""
335346
pass
336347

348+
def get_extended_info(self):
349+
""" Get scripted thread extended information.
350+
351+
Returns:
352+
List: A list containing the extended information for the scripted process.
353+
None is the thread as no extended information.
354+
"""
355+
return self.extended_info
356+
337357
ARM64_GPR = [ {'name': 'x0', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0, 'generic': 'arg0', 'alt-name': 'arg0'},
338358
{'name': 'x1', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1, 'dwarf': 1, 'generic': 'arg1', 'alt-name': 'arg1'},
339359
{'name': 'x2', 'bitsize': 64, 'offset': 16, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2, 'dwarf': 2, 'generic': 'arg2', 'alt-name': 'arg2'},

lldb/include/lldb/Core/StructuredDataImpl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class StructuredDataImpl {
8080
error.SetErrorString("No data to describe.");
8181
return error;
8282
}
83-
m_data_sp->Dump(stream, true);
83+
m_data_sp->GetDescription(stream);
8484
return error;
8585
}
8686
// Get the data's description.

lldb/include/lldb/Interpreter/CommandInterpreter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,9 @@ class CommandInterpreter : public Broadcaster,
551551
bool GetSaveSessionOnQuit() const;
552552
void SetSaveSessionOnQuit(bool enable);
553553

554+
bool GetOpenTranscriptInEditor() const;
555+
void SetOpenTranscriptInEditor(bool enable);
556+
554557
FileSpec GetSaveSessionDirectory() const;
555558
void SetSaveSessionDirectory(llvm::StringRef path);
556559

lldb/include/lldb/Interpreter/ScriptedProcessInterface.h

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class ScriptedProcessInterface : virtual public ScriptedInterface {
2424
CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
2525
StructuredData::DictionarySP args_sp,
2626
StructuredData::Generic *script_obj = nullptr) override {
27-
return nullptr;
27+
return {};
2828
}
2929

3030
virtual Status Launch() { return Status("ScriptedProcess did not launch"); }
@@ -41,22 +41,22 @@ class ScriptedProcessInterface : virtual public ScriptedInterface {
4141
return {};
4242
}
4343

44-
virtual StructuredData::DictionarySP GetThreadsInfo() { return nullptr; }
44+
virtual StructuredData::DictionarySP GetThreadsInfo() { return {}; }
4545

4646
virtual StructuredData::DictionarySP GetThreadWithID(lldb::tid_t tid) {
47-
return nullptr;
47+
return {};
4848
}
4949

5050
virtual StructuredData::DictionarySP GetRegistersForThread(lldb::tid_t tid) {
51-
return nullptr;
51+
return {};
5252
}
5353

5454
virtual lldb::DataExtractorSP
5555
ReadMemoryAtAddress(lldb::addr_t address, size_t size, Status &error) {
56-
return nullptr;
56+
return {};
5757
}
5858

59-
virtual StructuredData::ArraySP GetLoadedImages() { return nullptr; }
59+
virtual StructuredData::ArraySP GetLoadedImages() { return {}; }
6060

6161
virtual lldb::pid_t GetProcessID() { return LLDB_INVALID_PROCESS_ID; }
6262

@@ -66,10 +66,12 @@ class ScriptedProcessInterface : virtual public ScriptedInterface {
6666
return llvm::None;
6767
}
6868

69+
virtual StructuredData::DictionarySP GetMetadata() { return {}; }
70+
6971
protected:
7072
friend class ScriptedThread;
7173
virtual lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() {
72-
return nullptr;
74+
return {};
7375
}
7476
};
7577

@@ -79,7 +81,7 @@ class ScriptedThreadInterface : virtual public ScriptedInterface {
7981
CreatePluginObject(llvm::StringRef class_name, ExecutionContext &exe_ctx,
8082
StructuredData::DictionarySP args_sp,
8183
StructuredData::Generic *script_obj = nullptr) override {
82-
return nullptr;
84+
return {};
8385
}
8486

8587
virtual lldb::tid_t GetThreadID() { return LLDB_INVALID_THREAD_ID; }
@@ -90,15 +92,17 @@ class ScriptedThreadInterface : virtual public ScriptedInterface {
9092

9193
virtual llvm::Optional<std::string> GetQueue() { return llvm::None; }
9294

93-
virtual StructuredData::DictionarySP GetStopReason() { return nullptr; }
95+
virtual StructuredData::DictionarySP GetStopReason() { return {}; }
9496

95-
virtual StructuredData::ArraySP GetStackFrames() { return nullptr; }
97+
virtual StructuredData::ArraySP GetStackFrames() { return {}; }
9698

97-
virtual StructuredData::DictionarySP GetRegisterInfo() { return nullptr; }
99+
virtual StructuredData::DictionarySP GetRegisterInfo() { return {}; }
98100

99101
virtual llvm::Optional<std::string> GetRegisterContext() {
100102
return llvm::None;
101103
}
104+
105+
virtual StructuredData::ArraySP GetExtendedInfo() { return {}; }
102106
};
103107
} // namespace lldb_private
104108

lldb/include/lldb/Target/Process.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2447,6 +2447,13 @@ void PruneThreadPlans();
24472447
return Status("Not supported");
24482448
}
24492449

2450+
/// Fetch process defined metadata.
2451+
///
2452+
/// \return
2453+
/// A StructuredDataSP object which, if non-empty, will contain the
2454+
/// information related to the process.
2455+
virtual StructuredData::DictionarySP GetMetadata() { return nullptr; }
2456+
24502457
size_t AddImageToken(lldb::addr_t image_ptr);
24512458

24522459
lldb::addr_t GetImagePtrFromToken(size_t token) const;

0 commit comments

Comments
 (0)