Skip to content

Commit 96c733e

Browse files
authored
[lldb] Add support for PC-less scripted frames (#170805)
Scripted frames that materialize Python functions or other non-native code are PC-less by design, meaning they don't have valid program counter values. Previously, these frames would display invalid addresses (`0xffffffffffffffff`) in backtrace output. This patch updates `FormatEntity` to detect and suppress invalid address display for PC-less frames, adds fallback to frame methods when symbol context is unavailable, and modifies `StackFrame::GetSymbolContext` to skip PC-based symbol resolution for invalid addresses. The changes enable PC-less frames to display cleanly with proper function names, file paths, and line numbers, and allow for source display of foreign sources (like Python). Includes comprehensive test coverage demonstrating frames pointing to Python source files. Signed-off-by: Med Ismail Bennani <[email protected]>
1 parent 113b2d7 commit 96c733e

File tree

11 files changed

+553
-179
lines changed

11 files changed

+553
-179
lines changed

lldb/include/lldb/Target/StackID.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class StackID {
5252

5353
protected:
5454
friend class StackFrame;
55+
friend class SyntheticStackFrameList;
5556

5657
void SetPC(lldb::addr_t pc, Process *process);
5758
void SetCFA(lldb::addr_t cfa, Process *process);

lldb/source/Core/CoreProperties.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ let Definition = "debugger" in {
5959
Desc<"The default disassembly format string to use when disassembling instruction sequences.">;
6060
def FrameFormat: Property<"frame-format", "FormatEntity">,
6161
Global,
62-
DefaultStringValue<"frame #${frame.index}: ${ansi.fg.cyan}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}${frame.kind}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">,
62+
DefaultStringValue<"frame #${frame.index}: {${ansi.fg.cyan}${frame.pc}${ansi.normal}}{ ${module.file.basename}{`}}{${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}${frame.kind}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">,
6363
Desc<"The default frame format string to use when displaying stack frame information for threads.">;
6464
def NotiftVoid: Property<"notify-void", "Boolean">,
6565
Global,
@@ -235,7 +235,7 @@ let Definition = "debugger" in {
235235
Desc<"If true, LLDB will automatically escape non-printable and escape characters when formatting strings.">;
236236
def FrameFormatUnique: Property<"frame-format-unique", "FormatEntity">,
237237
Global,
238-
DefaultStringValue<"frame #${frame.index}: ${ansi.fg.cyan}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-without-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}${frame.kind}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">,
238+
DefaultStringValue<"frame #${frame.index}: {${ansi.fg.cyan}${frame.pc}${ansi.normal}}{ ${module.file.basename}{`}}{${function.name-without-args}{${frame.no-debug}${function.pc-offset}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}${frame.kind}{${function.is-optimized} [opt]}{${function.is-inlined} [inlined]}{${frame.is-artificial} [artificial]}\\\\n">,
239239
Desc<"The default frame format string to use when displaying stack frame information for threads from thread backtrace unique.">;
240240
def ShowAutosuggestion: Property<"show-autosuggestion", "Boolean">,
241241
Global,

lldb/source/Core/FormatEntity.cpp

Lines changed: 95 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,10 +1684,9 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
16841684
StackFrame *frame = exe_ctx->GetFramePtr();
16851685
if (frame) {
16861686
const Address &pc_addr = frame->GetFrameCodeAddress();
1687-
if (pc_addr.IsValid() || frame->IsSynthetic()) {
1687+
if (pc_addr.IsValid())
16881688
if (DumpAddressAndContent(s, sc, exe_ctx, pc_addr, false))
16891689
return true;
1690-
}
16911690
}
16921691
}
16931692
return false;
@@ -1808,70 +1807,91 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
18081807
return initial_function;
18091808

18101809
case Entry::Type::FunctionName: {
1811-
if (!sc)
1812-
return false;
1810+
if (sc) {
1811+
Language *language_plugin = nullptr;
1812+
bool language_plugin_handled = false;
1813+
StreamString ss;
18131814

1814-
Language *language_plugin = nullptr;
1815-
bool language_plugin_handled = false;
1816-
StreamString ss;
1815+
if (sc->function)
1816+
language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1817+
else if (sc->symbol)
1818+
language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
18171819

1818-
if (sc->function)
1819-
language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1820-
else if (sc->symbol)
1821-
language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
1820+
if (language_plugin)
1821+
language_plugin_handled = language_plugin->GetFunctionDisplayName(
1822+
*sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss);
18221823

1823-
if (language_plugin)
1824-
language_plugin_handled = language_plugin->GetFunctionDisplayName(
1825-
*sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss);
1824+
if (language_plugin_handled) {
1825+
s << ss.GetString();
1826+
return true;
1827+
}
18261828

1827-
if (language_plugin_handled) {
1828-
s << ss.GetString();
1829-
return true;
1829+
const char *name = sc->GetPossiblyInlinedFunctionName()
1830+
.GetName(Mangled::NamePreference::ePreferDemangled)
1831+
.AsCString();
1832+
if (name) {
1833+
s.PutCString(name);
1834+
return true;
1835+
}
18301836
}
18311837

1832-
const char *name = sc->GetPossiblyInlinedFunctionName()
1833-
.GetName(Mangled::NamePreference::ePreferDemangled)
1834-
.AsCString();
1835-
if (!name)
1836-
return false;
1837-
1838-
s.PutCString(name);
1839-
1840-
return true;
1838+
// Fallback to frame methods if available.
1839+
if (exe_ctx) {
1840+
StackFrame *frame = exe_ctx->GetFramePtr();
1841+
if (frame) {
1842+
const char *name = frame->GetFunctionName();
1843+
if (name) {
1844+
s.PutCString(name);
1845+
return true;
1846+
}
1847+
}
1848+
}
1849+
return false;
18411850
}
18421851

18431852
case Entry::Type::FunctionNameNoArgs: {
1844-
if (!sc)
1845-
return false;
1846-
1847-
Language *language_plugin = nullptr;
1848-
bool language_plugin_handled = false;
1849-
StreamString ss;
1850-
if (sc->function)
1851-
language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1852-
else if (sc->symbol)
1853-
language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
1854-
1855-
if (language_plugin)
1856-
language_plugin_handled = language_plugin->GetFunctionDisplayName(
1857-
*sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs,
1858-
ss);
1853+
if (sc) {
1854+
Language *language_plugin = nullptr;
1855+
bool language_plugin_handled = false;
1856+
StreamString ss;
1857+
if (sc->function)
1858+
language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1859+
else if (sc->symbol)
1860+
language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
1861+
1862+
if (language_plugin)
1863+
language_plugin_handled = language_plugin->GetFunctionDisplayName(
1864+
*sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs,
1865+
ss);
1866+
1867+
if (language_plugin_handled) {
1868+
s << ss.GetString();
1869+
return true;
1870+
}
18591871

1860-
if (language_plugin_handled) {
1861-
s << ss.GetString();
1862-
return true;
1872+
const char *name =
1873+
sc->GetPossiblyInlinedFunctionName()
1874+
.GetName(
1875+
Mangled::NamePreference::ePreferDemangledWithoutArguments)
1876+
.AsCString();
1877+
if (name) {
1878+
s.PutCString(name);
1879+
return true;
1880+
}
18631881
}
18641882

1865-
const char *name =
1866-
sc->GetPossiblyInlinedFunctionName()
1867-
.GetName(Mangled::NamePreference::ePreferDemangledWithoutArguments)
1868-
.AsCString();
1869-
if (!name)
1870-
return false;
1871-
1872-
s.PutCString(name);
1873-
1874-
return true;
1883+
// Fallback to frame methods if available.
1884+
if (exe_ctx) {
1885+
StackFrame *frame = exe_ctx->GetFramePtr();
1886+
if (frame) {
1887+
const char *name = frame->GetFunctionName();
1888+
if (name) {
1889+
s.PutCString(name);
1890+
return true;
1891+
}
1892+
}
1893+
}
1894+
return false;
18751895
}
18761896

18771897
case Entry::Type::FunctionPrefix:
@@ -1898,13 +1918,26 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
18981918
}
18991919

19001920
case Entry::Type::FunctionNameWithArgs: {
1901-
if (!sc)
1902-
return false;
1921+
if (sc) {
1922+
if (FormatFunctionNameForLanguage(s, exe_ctx, sc))
1923+
return true;
19031924

1904-
if (FormatFunctionNameForLanguage(s, exe_ctx, sc))
1905-
return true;
1925+
if (HandleFunctionNameWithArgs(s, exe_ctx, *sc))
1926+
return true;
1927+
}
19061928

1907-
return HandleFunctionNameWithArgs(s, exe_ctx, *sc);
1929+
// Fallback to frame methods if available.
1930+
if (exe_ctx) {
1931+
StackFrame *frame = exe_ctx->GetFramePtr();
1932+
if (frame) {
1933+
const char *name = frame->GetDisplayFunctionName();
1934+
if (name) {
1935+
s.PutCString(name);
1936+
return true;
1937+
}
1938+
}
1939+
}
1940+
return false;
19081941
}
19091942
case Entry::Type::FunctionMangledName: {
19101943
if (!sc)
@@ -1946,12 +1979,11 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
19461979
case Entry::Type::FunctionPCOffset:
19471980
if (exe_ctx) {
19481981
StackFrame *frame = exe_ctx->GetFramePtr();
1949-
if (frame) {
1982+
if (frame)
19501983
if (DumpAddressOffsetFromFunction(s, sc, exe_ctx,
19511984
frame->GetFrameCodeAddress(), false,
19521985
false, false))
19531986
return true;
1954-
}
19551987
}
19561988
return false;
19571989

@@ -1975,11 +2007,8 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
19752007

19762008
case Entry::Type::LineEntryFile:
19772009
if (sc && sc->line_entry.IsValid()) {
1978-
Module *module = sc->module_sp.get();
1979-
if (module) {
1980-
if (DumpFile(s, sc->line_entry.GetFile(), (FileKind)entry.number))
1981-
return true;
1982-
}
2010+
if (DumpFile(s, sc->line_entry.GetFile(), (FileKind)entry.number))
2011+
return true;
19832012
}
19842013
return false;
19852014

0 commit comments

Comments
 (0)