Author: jmolenda Date: Thu Sep 8 00:12:41 2016 New Revision: 280906 URL: http://llvm.org/viewvc/llvm-project?rev=280906&view=rev Log: I'm experimenting with changing how the mixed source & assembly mode in lldb works. I've been discussing this with Jim Ingham, Greg Clayton, and Kate Stone for the past week or two.
Previously lldb would print three source lines (centered on the line table entry line for the current line) followed by the assembly. It would print the context information (module`function + offset) before those three lines of source. Now lldb will print up to two lines before/after the line table entry. It prints two '*' characters for the line table line to make it clear what line is showing assembly. There is one line of whitespace before/after the source lines so the separation between source & assembly is clearer. I don't print the context line (module`function + offset). I stop printing context lines if it's a different line table entry, or if it's a source line I've already printed as context to another source line. If I have two line table entries one after another for the same source line (I get these often with clang - with different column information in them), I only print the source line once. I'm also using the target.process.thread.step-avoid-regexp setting (which keeps you from stepping into STL functions that have been inlined into your own code) and avoid printing any source lines from functions that match that regexp. When lldb disassembles into a new function, it will try to find the declaration line # for the function and print all of the source lines between the decl and the first line table entry (usually a { curly brace) so we have a good chance of including the arguments, at least with the debug info emitted by clang. Finally, the # of source lines of context to show has been separated from whether we're doing mixed source & assembly or not. Previously specifying 0 lines of context would turn off mixed source & assembly. I think there's room for improvement, and maybe some bugs I haven't found yet, but it's in good enough shape to upstream and iterate at this point. I'm not sure how best to indicate which source line is the actual line table # versus context lines. I'm using '**' right now. Both Kate and Greg had the initial idea to reuse '->' (normally used to indicate "currently executing source line") - I tried it but I wasn't thrilled, I'm too used to the established meaning of ->. Greg had the interesting idea of avoiding context source lines only in two line table entries in the same source file. So we'd print two lines before & after a source line, and then the next line table entry (if it was on the next source line after those two context lines) we'd display only the following two lines -- the previous two had just been printed. If an inline source line was printed between these two, though, we'd print the context lines for both of them. It's an interesting idea, and I want to see how it works with both -O0 and -O3 codegen where we have different amounts of inlining. <rdar://problem/27961419> Modified: lldb/trunk/include/lldb/Core/Disassembler.h lldb/trunk/source/Commands/CommandObjectDisassemble.cpp lldb/trunk/source/Core/Disassembler.cpp lldb/trunk/source/Target/StackFrame.cpp Modified: lldb/trunk/include/lldb/Core/Disassembler.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Disassembler.h?rev=280906&r1=280905&r2=280906&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/Disassembler.h (original) +++ lldb/trunk/include/lldb/Core/Disassembler.h Thu Sep 8 00:12:41 2016 @@ -22,7 +22,9 @@ #include "lldb/Core/EmulateInstruction.h" #include "lldb/Core/Opcode.h" #include "lldb/Core/PluginInterface.h" +#include "lldb/Host/FileSpec.h" #include "lldb/Interpreter/OptionValue.h" +#include "lldb/Symbol/LineEntry.h" #include "lldb/lldb-private.h" namespace lldb_private { @@ -314,6 +316,7 @@ public: const char *plugin_name, const char *flavor, const ExecutionContext &exe_ctx, const AddressRange &range, uint32_t num_instructions, + bool mixed_source_and_assembly, uint32_t num_mixed_context_lines, uint32_t options, Stream &strm); @@ -321,6 +324,7 @@ public: const char *plugin_name, const char *flavor, const ExecutionContext &exe_ctx, const Address &start, uint32_t num_instructions, + bool mixed_source_and_assembly, uint32_t num_mixed_context_lines, uint32_t options, Stream &strm); @@ -328,22 +332,21 @@ public: Disassemble(Debugger &debugger, const ArchSpec &arch, const char *plugin_name, const char *flavor, const ExecutionContext &exe_ctx, SymbolContextList &sc_list, uint32_t num_instructions, - uint32_t num_mixed_context_lines, uint32_t options, Stream &strm); + bool mixed_source_and_assembly, uint32_t num_mixed_context_lines, + uint32_t options, Stream &strm); - static bool Disassemble(Debugger &debugger, const ArchSpec &arch, - const char *plugin_name, const char *flavor, - const ExecutionContext &exe_ctx, - const ConstString &name, Module *module, - uint32_t num_instructions, - uint32_t num_mixed_context_lines, uint32_t options, - Stream &strm); + static bool + Disassemble(Debugger &debugger, const ArchSpec &arch, const char *plugin_name, + const char *flavor, const ExecutionContext &exe_ctx, + const ConstString &name, Module *module, + uint32_t num_instructions, bool mixed_source_and_assembly, + uint32_t num_mixed_context_lines, uint32_t options, Stream &strm); - static bool Disassemble(Debugger &debugger, const ArchSpec &arch, - const char *plugin_name, const char *flavor, - const ExecutionContext &exe_ctx, - uint32_t num_instructions, - uint32_t num_mixed_context_lines, uint32_t options, - Stream &strm); + static bool + Disassemble(Debugger &debugger, const ArchSpec &arch, const char *plugin_name, + const char *flavor, const ExecutionContext &exe_ctx, + uint32_t num_instructions, bool mixed_source_and_assembly, + uint32_t num_mixed_context_lines, uint32_t options, Stream &strm); //------------------------------------------------------------------ // Constructors and Destructors @@ -359,6 +362,7 @@ public: const ArchSpec &arch, const ExecutionContext &exe_ctx, uint32_t num_instructions, + bool mixed_source_and_assembly, uint32_t num_mixed_context_lines, uint32_t options, Stream &strm); @@ -388,6 +392,73 @@ public: const char *flavor) = 0; protected: + // SourceLine and SourceLinesToDisplay structures are only used in + // the mixed source and assembly display methods internal to this class. + + struct SourceLine { + FileSpec file; + uint32_t line; + + SourceLine() : file(), line(LLDB_INVALID_LINE_NUMBER) {} + + bool operator==(const SourceLine &rhs) const { + return file == rhs.file && line == rhs.line; + } + + bool operator!=(const SourceLine &rhs) const { + return file != rhs.file || line != rhs.line; + } + + bool IsValid() const { return line != LLDB_INVALID_LINE_NUMBER; } + }; + + struct SourceLinesToDisplay { + std::vector<SourceLine> lines; + + // index of the "current" source line, if we want to highlight that + // when displaying the source lines. (as opposed to the surrounding + // source lines provided to give context) + size_t current_source_line; + + // Whether to print a blank line at the end of the source lines. + bool print_source_context_end_eol; + + SourceLinesToDisplay() + : lines(), current_source_line(-1), print_source_context_end_eol(true) { + } + }; + + // Get the function's declaration line number, hopefully a line number earlier + // than the opening curly brace at the start of the function body. + static SourceLine GetFunctionDeclLineEntry(const SymbolContext &sc); + + // Add the provided SourceLine to the map of filenames-to-source-lines-seen. + static void AddLineToSourceLineTables( + SourceLine &line, + std::map<FileSpec, std::set<uint32_t>> &source_lines_seen); + + // Given a source line, determine if we should print it when we're doing + // mixed source & assembly output. + // We're currently using the target.process.thread.step-avoid-regexp setting + // (which is used for stepping over inlined STL functions by default) to + // determine what source lines to avoid showing. + // + // Returns true if this source line should be elided (if the source line + // should + // not be displayed). + static bool + ElideMixedSourceAndDisassemblyLine(const ExecutionContext &exe_ctx, + const SymbolContext &sc, SourceLine &line); + + static bool + ElideMixedSourceAndDisassemblyLine(const ExecutionContext &exe_ctx, + const SymbolContext &sc, LineEntry &line) { + SourceLine sl; + sl.file = line.file; + sl.line = line.line; + return ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, sl); + }; + //------------------------------------------------------------------ // Classes that inherit from Disassembler can see and modify these //------------------------------------------------------------------ Modified: lldb/trunk/source/Commands/CommandObjectDisassemble.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectDisassemble.cpp?rev=280906&r1=280905&r2=280906&view=diff ============================================================================== --- lldb/trunk/source/Commands/CommandObjectDisassemble.cpp (original) +++ lldb/trunk/source/Commands/CommandObjectDisassemble.cpp Thu Sep 8 00:12:41 2016 @@ -313,7 +313,7 @@ bool CommandObjectDisassemble::DoExecute } if (m_options.show_mixed && m_options.num_lines_context == 0) - m_options.num_lines_context = 1; + m_options.num_lines_context = 2; // Always show the PC in the disassembly uint32_t options = Disassembler::eOptionMarkPCAddress; @@ -336,7 +336,7 @@ bool CommandObjectDisassemble::DoExecute m_interpreter.GetDebugger(), m_options.arch, plugin_name, flavor_string, m_exe_ctx, name, nullptr, // Module * - m_options.num_instructions, + m_options.num_instructions, m_options.show_mixed, m_options.show_mixed ? m_options.num_lines_context : 0, options, result.GetOutputStream())) { result.SetStatus(eReturnStatusSuccessFinishResult); @@ -499,7 +499,7 @@ bool CommandObjectDisassemble::DoExecute if (Disassembler::Disassemble( m_interpreter.GetDebugger(), m_options.arch, plugin_name, flavor_string, m_exe_ctx, cur_range.GetBaseAddress(), - m_options.num_instructions, + m_options.num_instructions, m_options.show_mixed, m_options.show_mixed ? m_options.num_lines_context : 0, options, result.GetOutputStream())) { result.SetStatus(eReturnStatusSuccessFinishResult); @@ -547,6 +547,7 @@ bool CommandObjectDisassemble::DoExecute if (Disassembler::Disassemble( m_interpreter.GetDebugger(), m_options.arch, plugin_name, flavor_string, m_exe_ctx, cur_range, m_options.num_instructions, + m_options.show_mixed, m_options.show_mixed ? m_options.num_lines_context : 0, options, result.GetOutputStream())) { result.SetStatus(eReturnStatusSuccessFinishResult); Modified: lldb/trunk/source/Core/Disassembler.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Disassembler.cpp?rev=280906&r1=280905&r2=280906&view=diff ============================================================================== --- lldb/trunk/source/Core/Disassembler.cpp (original) +++ lldb/trunk/source/Core/Disassembler.cpp Thu Sep 8 00:12:41 2016 @@ -29,6 +29,7 @@ #include "lldb/Interpreter/OptionValue.h" #include "lldb/Interpreter/OptionValueArray.h" #include "lldb/Interpreter/OptionValueDictionary.h" +#include "lldb/Interpreter/OptionValueRegex.h" #include "lldb/Interpreter/OptionValueString.h" #include "lldb/Interpreter/OptionValueUInt64.h" #include "lldb/Symbol/Function.h" @@ -120,6 +121,7 @@ size_t Disassembler::Disassemble(Debugge const ExecutionContext &exe_ctx, SymbolContextList &sc_list, uint32_t num_instructions, + bool mixed_source_and_assembly, uint32_t num_mixed_context_lines, uint32_t options, Stream &strm) { size_t success_count = 0; @@ -136,8 +138,8 @@ size_t Disassembler::Disassemble(Debugge sc.GetAddressRange(scope, range_idx, use_inline_block_range, range); ++range_idx) { if (Disassemble(debugger, arch, plugin_name, flavor, exe_ctx, range, - num_instructions, num_mixed_context_lines, options, - strm)) { + num_instructions, mixed_source_and_assembly, + num_mixed_context_lines, options, strm)) { ++success_count; strm.EOL(); } @@ -151,6 +153,7 @@ bool Disassembler::Disassemble(Debugger const ExecutionContext &exe_ctx, const ConstString &name, Module *module, uint32_t num_instructions, + bool mixed_source_and_assembly, uint32_t num_mixed_context_lines, uint32_t options, Stream &strm) { SymbolContextList sc_list; @@ -169,8 +172,8 @@ bool Disassembler::Disassemble(Debugger if (sc_list.GetSize()) { return Disassemble(debugger, arch, plugin_name, flavor, exe_ctx, sc_list, - num_instructions, num_mixed_context_lines, options, - strm); + num_instructions, mixed_source_and_assembly, + num_mixed_context_lines, options, strm); } return false; } @@ -221,6 +224,7 @@ bool Disassembler::Disassemble(Debugger const ExecutionContext &exe_ctx, const AddressRange &disasm_range, uint32_t num_instructions, + bool mixed_source_and_assembly, uint32_t num_mixed_context_lines, uint32_t options, Stream &strm) { if (disasm_range.GetByteSize()) { @@ -239,8 +243,8 @@ bool Disassembler::Disassemble(Debugger return false; return PrintInstructions(disasm_sp.get(), debugger, arch, exe_ctx, - num_instructions, num_mixed_context_lines, - options, strm); + num_instructions, mixed_source_and_assembly, + num_mixed_context_lines, options, strm); } } return false; @@ -251,6 +255,7 @@ bool Disassembler::Disassemble(Debugger const ExecutionContext &exe_ctx, const Address &start_address, uint32_t num_instructions, + bool mixed_source_and_assembly, uint32_t num_mixed_context_lines, uint32_t options, Stream &strm) { if (num_instructions > 0) { @@ -265,17 +270,95 @@ bool Disassembler::Disassemble(Debugger if (bytes_disassembled == 0) return false; return PrintInstructions(disasm_sp.get(), debugger, arch, exe_ctx, - num_instructions, num_mixed_context_lines, - options, strm); + num_instructions, mixed_source_and_assembly, + num_mixed_context_lines, options, strm); } } return false; } +Disassembler::SourceLine +Disassembler::GetFunctionDeclLineEntry(const SymbolContext &sc) { + SourceLine decl_line; + if (sc.function && sc.line_entry.IsValid()) { + LineEntry prologue_end_line = sc.line_entry; + FileSpec func_decl_file; + uint32_t func_decl_line; + sc.function->GetStartLineSourceInfo(func_decl_file, func_decl_line); + if (func_decl_file == prologue_end_line.file || + func_decl_file == prologue_end_line.original_file) { + decl_line.file = func_decl_file; + decl_line.line = func_decl_line; + } + } + return decl_line; +} + +void Disassembler::AddLineToSourceLineTables( + SourceLine &line, + std::map<FileSpec, std::set<uint32_t>> &source_lines_seen) { + if (line.IsValid()) { + auto source_lines_seen_pos = source_lines_seen.find(line.file); + if (source_lines_seen_pos == source_lines_seen.end()) { + std::set<uint32_t> lines; + lines.insert(line.line); + source_lines_seen.emplace(line.file, lines); + } else { + source_lines_seen_pos->second.insert(line.line); + } + } +} + +bool Disassembler::ElideMixedSourceAndDisassemblyLine( + const ExecutionContext &exe_ctx, const SymbolContext &sc, + SourceLine &line) { + + // TODO: should we also check target.process.thread.step-avoid-libraries ? + + const RegularExpression *avoid_regex = nullptr; + + // Skip any line #0 entries - they are implementation details + if (line.line == 0) + return false; + + ThreadSP thread_sp = exe_ctx.GetThreadSP(); + if (thread_sp) { + avoid_regex = thread_sp->GetSymbolsToAvoidRegexp(); + } else { + TargetSP target_sp = exe_ctx.GetTargetSP(); + if (target_sp) { + Error error; + OptionValueSP value_sp = target_sp->GetDebugger().GetPropertyValue( + &exe_ctx, "target.process.thread.step-avoid-regexp", false, error); + if (value_sp && value_sp->GetType() == OptionValue::eTypeRegex) { + OptionValueRegex *re = value_sp->GetAsRegex(); + if (re) { + avoid_regex = re->GetCurrentValue(); + } + } + } + } + if (avoid_regex && sc.symbol != nullptr) { + const char *function_name = + sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments) + .GetCString(); + if (function_name) { + RegularExpression::Match regex_match(1); + if (avoid_regex->Execute(function_name, ®ex_match)) { + // skip this source line + return true; + } + } + } + // don't skip this source line + return false; +} + bool Disassembler::PrintInstructions(Disassembler *disasm_ptr, Debugger &debugger, const ArchSpec &arch, const ExecutionContext &exe_ctx, uint32_t num_instructions, + bool mixed_source_and_assembly, uint32_t num_mixed_context_lines, uint32_t options, Stream &strm) { // We got some things disassembled... @@ -289,7 +372,7 @@ bool Disassembler::PrintInstructions(Dis uint32_t offset = 0; SymbolContext sc; SymbolContext prev_sc; - AddressRange sc_range; + AddressRange current_source_line_range; const Address *pc_addr_ptr = nullptr; StackFrame *frame = exe_ctx.GetFramePtr(); @@ -317,6 +400,16 @@ bool Disassembler::PrintInstructions(Dis // First pass: step through the list of instructions, // find how long the initial addresses strings are, insert padding // in the second pass so the opcodes all line up nicely. + + // Also build up the source line mapping if this is mixed source & assembly + // mode. + // Calculate the source line for each assembly instruction (eliding inlined + // functions + // which the user wants to skip). + + std::map<FileSpec, std::set<uint32_t>> source_lines_seen; + Symbol *previous_symbol = nullptr; + size_t address_text_size = 0; for (size_t i = 0; i < num_instructions_found; ++i) { Instruction *inst = @@ -325,8 +418,9 @@ bool Disassembler::PrintInstructions(Dis const Address &addr = inst->GetAddress(); ModuleSP module_sp(addr.GetModule()); if (module_sp) { - const uint32_t resolve_mask = - eSymbolContextFunction | eSymbolContextSymbol; + const uint32_t resolve_mask = eSymbolContextFunction | + eSymbolContextSymbol | + eSymbolContextLineEntry; uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(addr, resolve_mask, sc); if (resolved_mask) { @@ -336,18 +430,46 @@ bool Disassembler::PrintInstructions(Dis size_t cur_line = strmstr.GetSizeOfLastLine(); if (cur_line > address_text_size) address_text_size = cur_line; + + // Add entries to our "source_lines_seen" map+set which list which + // sources lines occur in this disassembly session. We will print + // lines of context around a source line, but we don't want to print + // a source line that has a line table entry of its own - we'll leave + // that source line to be printed when it actually occurs in the + // disassembly. + + if (mixed_source_and_assembly && sc.line_entry.IsValid()) { + if (sc.symbol != previous_symbol) { + SourceLine decl_line = GetFunctionDeclLineEntry(sc); + if (ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, decl_line) == + false) + AddLineToSourceLineTables(decl_line, source_lines_seen); + } + if (sc.line_entry.IsValid()) { + SourceLine this_line; + this_line.file = sc.line_entry.file; + this_line.line = sc.line_entry.line; + if (ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, this_line) == + false) + AddLineToSourceLineTables(this_line, source_lines_seen); + } + } } sc.Clear(false); } } } + previous_symbol = nullptr; + SourceLine previous_line; for (size_t i = 0; i < num_instructions_found; ++i) { Instruction *inst = disasm_ptr->GetInstructionList().GetInstructionAtIndex(i).get(); + if (inst) { const Address &addr = inst->GetAddress(); const bool inst_is_at_pc = pc_addr_ptr && addr == *pc_addr_ptr; + SourceLinesToDisplay source_lines_to_display; prev_sc = sc; @@ -356,26 +478,121 @@ bool Disassembler::PrintInstructions(Dis uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress( addr, eSymbolContextEverything, sc); if (resolved_mask) { - if (num_mixed_context_lines) { - if (!sc_range.ContainsFileAddress(addr)) { - sc.GetAddressRange(scope, 0, use_inline_block_range, sc_range); - - if (sc != prev_sc) { - if (offset != 0) - strm.EOL(); - - sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, - true, false, false, true); - strm.EOL(); - - if (sc.comp_unit && sc.line_entry.IsValid()) { - source_manager.DisplaySourceLinesWithLineNumbers( - sc.line_entry.file, sc.line_entry.line, - num_mixed_context_lines, num_mixed_context_lines, - ((inst_is_at_pc && (options & eOptionMarkPCSourceLine)) - ? "->" - : ""), - &strm); + if (mixed_source_and_assembly) { + + // If we've started a new function (non-inlined), print all of the + // source lines from the + // function declaration until the first line table entry - typically + // the opening curly brace of + // the function. + if (previous_symbol != sc.symbol) { + // The default disassembly format puts an extra blank line between + // functions - so + // when we're displaying the source context for a function, we + // don't want to add + // a blank line after the source context or we'll end up with two + // of them. + if (previous_symbol != nullptr) + source_lines_to_display.print_source_context_end_eol = false; + + previous_symbol = sc.symbol; + if (sc.function && sc.line_entry.IsValid()) { + LineEntry prologue_end_line = sc.line_entry; + if (ElideMixedSourceAndDisassemblyLine( + exe_ctx, sc, prologue_end_line) == false) { + FileSpec func_decl_file; + uint32_t func_decl_line; + sc.function->GetStartLineSourceInfo(func_decl_file, + func_decl_line); + if (func_decl_file == prologue_end_line.file || + func_decl_file == prologue_end_line.original_file) { + // Add all the lines between the function declaration + // and the first non-prologue source line to the list + // of lines to print. + for (uint32_t lineno = func_decl_line; + lineno <= prologue_end_line.line; lineno++) { + SourceLine this_line; + this_line.file = func_decl_file; + this_line.line = lineno; + source_lines_to_display.lines.push_back(this_line); + } + // Mark the last line as the "current" one. Usually + // this is the open curly brace. + if (source_lines_to_display.lines.size() > 0) + source_lines_to_display.current_source_line = + source_lines_to_display.lines.size() - 1; + } + } + } + sc.GetAddressRange(scope, 0, use_inline_block_range, + current_source_line_range); + } + + // If we've left a previous source line's address range, print a new + // source line + if (!current_source_line_range.ContainsFileAddress(addr)) { + sc.GetAddressRange(scope, 0, use_inline_block_range, + current_source_line_range); + + if (sc != prev_sc && sc.comp_unit && sc.line_entry.IsValid()) { + SourceLine this_line; + this_line.file = sc.line_entry.file; + this_line.line = sc.line_entry.line; + + if (ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, + this_line) == false) { + // Only print this source line if it is different from the + // last source line we printed. There may have been inlined + // functions between these lines that we elided, resulting in + // the same line being printed twice in a row for a contiguous + // block of assembly instructions. + if (this_line != previous_line) { + + std::vector<uint32_t> previous_lines; + for (int i = 0; + i < num_mixed_context_lines && + (this_line.line - num_mixed_context_lines) > 0; + i++) { + uint32_t line = + this_line.line - num_mixed_context_lines + i; + auto pos = source_lines_seen.find(this_line.file); + if (pos != source_lines_seen.end()) { + if (pos->second.count(line) == 1) { + previous_lines.clear(); + } else { + previous_lines.push_back(line); + } + } + } + for (size_t i = 0; i < previous_lines.size(); i++) { + SourceLine previous_line; + previous_line.file = this_line.file; + previous_line.line = previous_lines[i]; + auto pos = source_lines_seen.find(previous_line.file); + if (pos != source_lines_seen.end()) { + pos->second.insert(previous_line.line); + } + source_lines_to_display.lines.push_back(previous_line); + } + + source_lines_to_display.lines.push_back(this_line); + source_lines_to_display.current_source_line = + source_lines_to_display.lines.size() - 1; + + for (int i = 0; i < num_mixed_context_lines; i++) { + SourceLine next_line; + next_line.file = this_line.file; + next_line.line = this_line.line + i + 1; + auto pos = source_lines_seen.find(next_line.file); + if (pos != source_lines_seen.end()) { + if (pos->second.count(next_line.line) == 1) + break; + pos->second.insert(next_line.line); + } + source_lines_to_display.lines.push_back(next_line); + } + } + previous_line = this_line; } } } @@ -385,6 +602,24 @@ bool Disassembler::PrintInstructions(Dis } } + if (source_lines_to_display.lines.size() > 0) { + strm.EOL(); + for (size_t idx = 0; idx < source_lines_to_display.lines.size(); + idx++) { + SourceLine ln = source_lines_to_display.lines[idx]; + const char *line_highlight = ""; + if (inst_is_at_pc && (options & eOptionMarkPCSourceLine)) { + line_highlight = "->"; + } else if (idx == source_lines_to_display.current_source_line) { + line_highlight = "**"; + } + source_manager.DisplaySourceLinesWithLineNumbers( + ln.file, ln.line, 0, 0, line_highlight, &strm); + } + if (source_lines_to_display.print_source_context_end_eol) + strm.EOL(); + } + const bool show_bytes = (options & eOptionShowBytes) != 0; inst->Dump(&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc, &prev_sc, nullptr, address_text_size); @@ -401,6 +636,7 @@ bool Disassembler::Disassemble(Debugger const char *plugin_name, const char *flavor, const ExecutionContext &exe_ctx, uint32_t num_instructions, + bool mixed_source_and_assembly, uint32_t num_mixed_context_lines, uint32_t options, Stream &strm) { AddressRange range; @@ -422,7 +658,8 @@ bool Disassembler::Disassemble(Debugger } return Disassemble(debugger, arch, plugin_name, flavor, exe_ctx, range, - num_instructions, num_mixed_context_lines, options, strm); + num_instructions, mixed_source_and_assembly, + num_mixed_context_lines, options, strm); } Instruction::Instruction(const Address &address, AddressClass addr_class) Modified: lldb/trunk/source/Target/StackFrame.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StackFrame.cpp?rev=280906&r1=280905&r2=280906&view=diff ============================================================================== --- lldb/trunk/source/Target/StackFrame.cpp (original) +++ lldb/trunk/source/Target/StackFrame.cpp Thu Sep 8 00:12:41 2016 @@ -229,7 +229,7 @@ const char *StackFrame::Disassemble() { const char *flavor = nullptr; Disassembler::Disassemble(target->GetDebugger(), target->GetArchitecture(), plugin_name, flavor, - exe_ctx, 0, 0, 0, m_disassembly); + exe_ctx, 0, false, 0, 0, m_disassembly); } if (m_disassembly.GetSize() == 0) return nullptr; @@ -853,10 +853,9 @@ ValueObjectSP StackFrame::GetValueForVar } else { ValueObjectSP synthetic = valobj_sp->GetSyntheticValue(); if (no_synth_child /* synthetic is forbidden */ || - !synthetic /* no synthetic */ - || - synthetic == valobj_sp) /* synthetic is the same as the - original object */ + !synthetic /* no synthetic */ + || synthetic == valobj_sp) /* synthetic is the same as the + original object */ { valobj_sp->GetExpressionPath(var_expr_path_strm, false); error.SetErrorStringWithFormat( @@ -1906,10 +1905,11 @@ bool StackFrame::GetStatus(Stream &strm, target_arch.GetMaximumOpcodeByteSize()); const char *plugin_name = nullptr; const char *flavor = nullptr; - Disassembler::Disassemble(target->GetDebugger(), target_arch, - plugin_name, flavor, exe_ctx, pc_range, - disasm_lines, 0, - Disassembler::eOptionMarkPCAddress, strm); + const bool mixed_source_and_assembly = false; + Disassembler::Disassemble( + target->GetDebugger(), target_arch, plugin_name, flavor, + exe_ctx, pc_range, disasm_lines, mixed_source_and_assembly, 0, + Disassembler::eOptionMarkPCAddress, strm); } } break; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits