@@ -657,18 +657,31 @@ std::optional<protocol::Source> DAP::ResolveSource(const lldb::SBFrame &frame) {
657657 if (!frame.IsValid ())
658658 return std::nullopt ;
659659
660- const lldb::SBAddress frame_pc = frame.GetPCAddress ();
661- if (DisplayAssemblySource (debugger, frame_pc))
660+ // IMPORTANT: Get line entry from symbol context, NOT from PC address.
661+ // When a frame's PC points to a return address (the instruction
662+ // after a call), that address may have line number 0 for compiler generated
663+ // code.
664+ //
665+ // EXAMPLE: If PC is at 0x1004 (frame return address after the call
666+ // instruction) with no line info, but 0x1003 (in the middle of previous call
667+ // instruction) is at line 42, symbol context returns line 42.
668+ //
669+ // NOTE: This issue is non-deterministic and depends on compiler debug info
670+ // generation, making it difficult to create a reliable automated test.
671+ const lldb::SBLineEntry frame_line_entry = frame.GetLineEntry ();
672+ if (DisplayAssemblySource (debugger, frame_line_entry)) {
673+ const lldb::SBAddress frame_pc = frame.GetPCAddress ();
662674 return ResolveAssemblySource (frame_pc);
675+ }
663676
664- return CreateSource (frame. GetLineEntry () .GetFileSpec ());
677+ return CreateSource (frame_line_entry .GetFileSpec ());
665678}
666679
667680std::optional<protocol::Source> DAP::ResolveSource (lldb::SBAddress address) {
668- if (DisplayAssemblySource (debugger, address))
681+ lldb::SBLineEntry line_entry = GetLineEntryForAddress (target, address);
682+ if (DisplayAssemblySource (debugger, line_entry))
669683 return ResolveAssemblySource (address);
670684
671- lldb::SBLineEntry line_entry = GetLineEntryForAddress (target, address);
672685 if (!line_entry.IsValid ())
673686 return std::nullopt ;
674687
0 commit comments