@@ -26,16 +26,14 @@ namespace lldb_dap {
2626// / `supportsDisassembleRequest` is true.
2727llvm::Expected<DisassembleResponseBody>
2828DisassembleRequestHandler::Run (const DisassembleArguments &args) const {
29- std::vector<DisassembledInstruction> instructions;
30-
3129 std::optional<lldb::addr_t > addr_opt =
3230 DecodeMemoryReference (args.memoryReference );
3331 if (!addr_opt.has_value ())
3432 return llvm::make_error<DAPError>(" Malformed memory reference: " +
3533 args.memoryReference );
3634
3735 lldb::addr_t addr_ptr = *addr_opt;
38- addr_ptr += args.instructionOffset .value_or (0 );
36+ addr_ptr += args.offset .value_or (0 );
3937 lldb::SBAddress addr (addr_ptr, dap.target );
4038 if (!addr.IsValid ())
4139 return llvm::make_error<DAPError>(
@@ -56,100 +54,185 @@ DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
5654 }
5755 }
5856
57+ int64_t instructionOffset = args.instructionOffset .value_or (0 );
58+ if (instructionOffset > 0 ) {
59+ lldb::SBInstructionList forward_insts = dap.target .ReadInstructions (
60+ addr, instructionOffset + 1 , flavor_string.c_str ());
61+ if (forward_insts.GetSize () != static_cast <size_t >(instructionOffset + 1 )) {
62+ return llvm::make_error<DAPError>(
63+ " Failed to disassemble instructions after " +
64+ std::to_string (instructionOffset) +
65+ " instructions from the given address." );
66+ }
67+
68+ addr = forward_insts.GetInstructionAtIndex (instructionOffset).GetAddress ();
69+ }
70+
71+ const bool resolve_symbols = args.resolveSymbols .value_or (false );
72+ std::vector<DisassembledInstruction> instructions;
73+ if (instructionOffset < 0 )
74+ instructions = disassembleBackwards (addr, std::abs (instructionOffset),
75+ flavor_string.c_str (), resolve_symbols);
76+
77+ const auto instructions_left = args.instructionCount - instructions.size ();
5978 lldb::SBInstructionList insts = dap.target .ReadInstructions (
60- addr, args. instructionCount , flavor_string.c_str ());
79+ addr, instructions_left , flavor_string.c_str ());
6180
6281 if (!insts.IsValid ())
6382 return llvm::make_error<DAPError>(
6483 " Failed to find instructions for memory address." );
6584
66- const bool resolve_symbols = args. resolveSymbols . value_or ( false );
85+ // add the disassembly from the given address forward
6786 const auto num_insts = insts.GetSize ();
68- for (size_t i = 0 ; i < num_insts; ++i) {
87+ for (size_t i = 0 ;
88+ i < num_insts && instructions.size () < args.instructionCount ; ++i) {
6989 lldb::SBInstruction inst = insts.GetInstructionAtIndex (i);
70- auto addr = inst.GetAddress ();
71- const auto inst_addr = addr.GetLoadAddress (dap.target );
72- const char *m = inst.GetMnemonic (dap.target );
73- const char *o = inst.GetOperands (dap.target );
74- const char *c = inst.GetComment (dap.target );
75- auto d = inst.GetData (dap.target );
76-
77- std::string bytes;
78- llvm::raw_string_ostream sb (bytes);
79- for (unsigned i = 0 ; i < inst.GetByteSize (); i++) {
80- lldb::SBError error;
81- uint8_t b = d.GetUnsignedInt8 (error, i);
82- if (error.Success ()) {
83- sb << llvm::format (" %2.2x " , b);
90+ instructions.push_back (
91+ SBInstructionToDisassembledInstruction (inst, resolve_symbols));
92+ }
93+
94+ // Pad the instructions with invalid instructions if needed.
95+ if (instructions.size () < args.instructionCount )
96+ for (size_t i = instructions.size (); i < args.instructionCount ; ++i)
97+ instructions.push_back (GetInvalidInstruction ());
98+
99+ return DisassembleResponseBody{std::move (instructions)};
100+ }
101+
102+ std::vector<protocol::DisassembledInstruction>
103+ DisassembleRequestHandler::disassembleBackwards (
104+ lldb::SBAddress &addr, const uint32_t instruction_count,
105+ const char *flavor_string, bool resolve_symbols) const {
106+ std::vector<DisassembledInstruction> instructions;
107+
108+ // TODO: Simply disassemble from `addr` - `instruction_count` *
109+ // `instruction_size` in architectures with a fixed instruction size.
110+
111+ // need to disassemble backwards, let's try from the start of the symbol if
112+ // available.
113+ auto symbol = addr.GetSymbol ();
114+ if (symbol.IsValid ()) {
115+ // add valid instructions before the current instruction using the symbol.
116+ lldb::SBInstructionList symbol_insts = dap.target .ReadInstructions (
117+ symbol.GetStartAddress (), addr, flavor_string);
118+ if (symbol_insts.IsValid ()) {
119+ size_t backwards_insts_start =
120+ symbol_insts.GetSize () >= instruction_count
121+ ? symbol_insts.GetSize () - instruction_count
122+ : 0 ;
123+ for (size_t i = backwards_insts_start;
124+ i < symbol_insts.GetSize () &&
125+ instructions.size () < instruction_count;
126+ ++i) {
127+ lldb::SBInstruction inst = symbol_insts.GetInstructionAtIndex (i);
128+ instructions.push_back (
129+ SBInstructionToDisassembledInstruction (inst, resolve_symbols));
84130 }
85131 }
132+ }
86133
87- DisassembledInstruction disassembled_inst;
88- disassembled_inst.address = inst_addr;
89- disassembled_inst.instructionBytes =
90- bytes.size () > 0 ? bytes.substr (0 , bytes.size () - 1 ) : " " ;
91-
92- std::string instruction;
93- llvm::raw_string_ostream si (instruction);
94-
95- lldb::SBSymbol symbol = addr.GetSymbol ();
96- // Only add the symbol on the first line of the function.
97- if (symbol.IsValid () && symbol.GetStartAddress () == addr) {
98- // If we have a valid symbol, append it as a label prefix for the first
99- // instruction. This is so you can see the start of a function/callsite
100- // in the assembly, at the moment VS Code (1.80) does not visualize the
101- // symbol associated with the assembly instruction.
102- si << (symbol.GetMangledName () != nullptr ? symbol.GetMangledName ()
103- : symbol.GetName ())
104- << " : " ;
105-
106- if (resolve_symbols)
107- disassembled_inst.symbol = symbol.GetDisplayName ();
108- }
134+ // pad the instructions with invalid instructions if needed.
135+ while (instructions.size () < instruction_count) {
136+ instructions.insert (instructions.begin (), GetInvalidInstruction ());
137+ }
109138
110- si << llvm::formatv (" {0,7} {1,12}" , m, o);
111- if (c && c[0 ]) {
112- si << " ; " << c;
113- }
139+ return instructions;
140+ }
141+
142+ DisassembledInstruction
143+ DisassembleRequestHandler::SBInstructionToDisassembledInstruction (
144+ lldb::SBInstruction &inst, bool resolve_symbols) const {
145+ if (!inst.IsValid ())
146+ return GetInvalidInstruction ();
147+
148+ auto addr = inst.GetAddress ();
149+ const auto inst_addr = addr.GetLoadAddress (dap.target );
150+ const char *m = inst.GetMnemonic (dap.target );
151+ const char *o = inst.GetOperands (dap.target );
152+ const char *c = inst.GetComment (dap.target );
153+ auto d = inst.GetData (dap.target );
154+
155+ std::string bytes;
156+ llvm::raw_string_ostream sb (bytes);
157+ for (unsigned i = 0 ; i < inst.GetByteSize (); i++) {
158+ lldb::SBError error;
159+ uint8_t b = d.GetUnsignedInt8 (error, i);
160+ if (error.Success ())
161+ sb << llvm::format (" %2.2x " , b);
162+ }
114163
115- disassembled_inst.instruction = instruction;
116-
117- auto line_entry = addr.GetLineEntry ();
118- // If the line number is 0 then the entry represents a compiler generated
119- // location.
120- if (line_entry.GetStartAddress () == addr && line_entry.IsValid () &&
121- line_entry.GetFileSpec ().IsValid () && line_entry.GetLine () != 0 ) {
122- auto source = CreateSource (line_entry);
123- disassembled_inst.location = std::move (source);
124-
125- const auto line = line_entry.GetLine ();
126- if (line != 0 && line != LLDB_INVALID_LINE_NUMBER)
127- disassembled_inst.line = line;
128-
129- const auto column = line_entry.GetColumn ();
130- if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER)
131- disassembled_inst.column = column;
132-
133- auto end_line_entry = line_entry.GetEndAddress ().GetLineEntry ();
134- if (end_line_entry.IsValid () &&
135- end_line_entry.GetFileSpec () == line_entry.GetFileSpec ()) {
136- const auto end_line = end_line_entry.GetLine ();
137- if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER &&
138- end_line != line) {
139- disassembled_inst.endLine = end_line;
140-
141- const auto end_column = end_line_entry.GetColumn ();
142- if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER &&
143- end_column != column)
144- disassembled_inst.endColumn = end_column - 1 ;
145- }
164+ DisassembledInstruction disassembled_inst;
165+ disassembled_inst.address = inst_addr;
166+ disassembled_inst.instructionBytes =
167+ bytes.size () > 0 ? bytes.substr (0 , bytes.size () - 1 ) : " " ;
168+
169+ std::string instruction;
170+ llvm::raw_string_ostream si (instruction);
171+
172+ lldb::SBSymbol symbol = addr.GetSymbol ();
173+ // Only add the symbol on the first line of the function.
174+ if (symbol.IsValid () && symbol.GetStartAddress () == addr) {
175+ // If we have a valid symbol, append it as a label prefix for the first
176+ // instruction. This is so you can see the start of a function/callsite
177+ // in the assembly, at the moment VS Code (1.80) does not visualize the
178+ // symbol associated with the assembly instruction.
179+ si << (symbol.GetMangledName () != nullptr ? symbol.GetMangledName ()
180+ : symbol.GetName ())
181+ << " : " ;
182+
183+ if (resolve_symbols)
184+ disassembled_inst.symbol = symbol.GetDisplayName ();
185+ }
186+
187+ si << llvm::formatv (" {0,7} {1,12}" , m, o);
188+ if (c && c[0 ]) {
189+ si << " ; " << c;
190+ }
191+
192+ disassembled_inst.instruction = std::move (instruction);
193+
194+ auto line_entry = addr.GetLineEntry ();
195+ // If the line number is 0 then the entry represents a compiler generated
196+ // location.
197+
198+ if (line_entry.GetStartAddress () == addr && line_entry.IsValid () &&
199+ line_entry.GetFileSpec ().IsValid () && line_entry.GetLine () != 0 ) {
200+ auto source = CreateSource (line_entry);
201+ disassembled_inst.location = std::move (source);
202+
203+ const auto line = line_entry.GetLine ();
204+ if (line != 0 && line != LLDB_INVALID_LINE_NUMBER)
205+ disassembled_inst.line = line;
206+
207+ const auto column = line_entry.GetColumn ();
208+ if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER)
209+ disassembled_inst.column = column;
210+
211+ auto end_line_entry = line_entry.GetEndAddress ().GetLineEntry ();
212+ if (end_line_entry.IsValid () &&
213+ end_line_entry.GetFileSpec () == line_entry.GetFileSpec ()) {
214+ const auto end_line = end_line_entry.GetLine ();
215+ if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER &&
216+ end_line != line) {
217+ disassembled_inst.endLine = end_line;
218+
219+ const auto end_column = end_line_entry.GetColumn ();
220+ if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER &&
221+ end_column != column)
222+ disassembled_inst.endColumn = end_column - 1 ;
146223 }
147224 }
148-
149- instructions.push_back (std::move (disassembled_inst));
150225 }
151226
152- return DisassembleResponseBody{std::move (instructions)};
227+ return disassembled_inst;
228+ }
229+
230+ DisassembledInstruction
231+ DisassembleRequestHandler::GetInvalidInstruction () const {
232+ DisassembledInstruction invalid_inst;
233+ invalid_inst.presentationHint =
234+ DisassembledInstruction::eDisassembledInstructionPresentationHintInvalid;
235+ return invalid_inst;
153236}
154237
155238} // namespace lldb_dap
0 commit comments