Skip to content

Commit 6d82a21

Browse files
committed
[lldb] Add support for PC-less scripted frames (llvm#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]> (cherry picked from commit 96c733e)
1 parent 7b6a6bf commit 6d82a21

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
@@ -61,6 +61,7 @@ class StackID {
6161

6262
protected:
6363
friend class StackFrame;
64+
friend class SyntheticStackFrameList;
6465

6566
void SetPC(lldb::addr_t pc, Process *process);
6667
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
@@ -132,7 +132,7 @@ let Definition = "debugger" in {
132132
Desc<"The default disassembly format string to use when disassembling instruction sequences.">;
133133
def FrameFormat: Property<"frame-format", "FormatEntity">,
134134
Global,
135-
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">,
135+
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">,
136136
Desc<"The default frame format string to use when displaying stack frame information for threads.">;
137137
def NotiftVoid: Property<"notify-void", "Boolean">,
138138
Global,
@@ -306,7 +306,7 @@ let Definition = "debugger" in {
306306
Desc<"If true, LLDB will automatically escape non-printable and escape characters when formatting strings.">;
307307
def FrameFormatUnique: Property<"frame-format-unique", "FormatEntity">,
308308
Global,
309-
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">,
309+
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">,
310310
Desc<"The default frame format string to use when displaying stack frame information for threads from thread backtrace unique.">;
311311
def ShowAutosuggestion: Property<"show-autosuggestion", "Boolean">,
312312
Global,

lldb/source/Core/FormatEntity.cpp

Lines changed: 95 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,10 +1692,9 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
16921692
StackFrame *frame = exe_ctx->GetFramePtr();
16931693
if (frame) {
16941694
const Address &pc_addr = frame->GetFrameCodeAddress();
1695-
if (pc_addr.IsValid() || frame->IsSynthetic()) {
1695+
if (pc_addr.IsValid())
16961696
if (DumpAddressAndContent(s, sc, exe_ctx, pc_addr, false))
16971697
return true;
1698-
}
16991698
}
17001699
}
17011700
return false;
@@ -1816,70 +1815,91 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
18161815
return initial_function;
18171816

18181817
case Entry::Type::FunctionName: {
1819-
if (!sc)
1820-
return false;
1818+
if (sc) {
1819+
Language *language_plugin = nullptr;
1820+
bool language_plugin_handled = false;
1821+
StreamString ss;
18211822

1822-
Language *language_plugin = nullptr;
1823-
bool language_plugin_handled = false;
1824-
StreamString ss;
1823+
if (sc->function)
1824+
language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1825+
else if (sc->symbol)
1826+
language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
18251827

1826-
if (sc->function)
1827-
language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1828-
else if (sc->symbol)
1829-
language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
1828+
if (language_plugin)
1829+
language_plugin_handled = language_plugin->GetFunctionDisplayName(
1830+
*sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss);
18301831

1831-
if (language_plugin)
1832-
language_plugin_handled = language_plugin->GetFunctionDisplayName(
1833-
*sc, exe_ctx, Language::FunctionNameRepresentation::eName, ss);
1832+
if (language_plugin_handled) {
1833+
s << ss.GetString();
1834+
return true;
1835+
}
18341836

1835-
if (language_plugin_handled) {
1836-
s << ss.GetString();
1837-
return true;
1837+
const char *name = sc->GetPossiblyInlinedFunctionName()
1838+
.GetName(Mangled::NamePreference::ePreferDemangled)
1839+
.AsCString();
1840+
if (name) {
1841+
s.PutCString(name);
1842+
return true;
1843+
}
18381844
}
18391845

1840-
const char *name = sc->GetPossiblyInlinedFunctionName()
1841-
.GetName(Mangled::NamePreference::ePreferDemangled)
1842-
.AsCString();
1843-
if (!name)
1844-
return false;
1845-
1846-
s.PutCString(name);
1847-
1848-
return true;
1846+
// Fallback to frame methods if available.
1847+
if (exe_ctx) {
1848+
StackFrame *frame = exe_ctx->GetFramePtr();
1849+
if (frame) {
1850+
const char *name = frame->GetFunctionName();
1851+
if (name) {
1852+
s.PutCString(name);
1853+
return true;
1854+
}
1855+
}
1856+
}
1857+
return false;
18491858
}
18501859

18511860
case Entry::Type::FunctionNameNoArgs: {
1852-
if (!sc)
1853-
return false;
1854-
1855-
Language *language_plugin = nullptr;
1856-
bool language_plugin_handled = false;
1857-
StreamString ss;
1858-
if (sc->function)
1859-
language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1860-
else if (sc->symbol)
1861-
language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
1862-
1863-
if (language_plugin)
1864-
language_plugin_handled = language_plugin->GetFunctionDisplayName(
1865-
*sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs,
1866-
ss);
1861+
if (sc) {
1862+
Language *language_plugin = nullptr;
1863+
bool language_plugin_handled = false;
1864+
StreamString ss;
1865+
if (sc->function)
1866+
language_plugin = Language::FindPlugin(sc->function->GetLanguage());
1867+
else if (sc->symbol)
1868+
language_plugin = Language::FindPlugin(sc->symbol->GetLanguage());
1869+
1870+
if (language_plugin)
1871+
language_plugin_handled = language_plugin->GetFunctionDisplayName(
1872+
*sc, exe_ctx, Language::FunctionNameRepresentation::eNameWithNoArgs,
1873+
ss);
1874+
1875+
if (language_plugin_handled) {
1876+
s << ss.GetString();
1877+
return true;
1878+
}
18671879

1868-
if (language_plugin_handled) {
1869-
s << ss.GetString();
1870-
return true;
1880+
const char *name =
1881+
sc->GetPossiblyInlinedFunctionName()
1882+
.GetName(
1883+
Mangled::NamePreference::ePreferDemangledWithoutArguments)
1884+
.AsCString();
1885+
if (name) {
1886+
s.PutCString(name);
1887+
return true;
1888+
}
18711889
}
18721890

1873-
const char *name =
1874-
sc->GetPossiblyInlinedFunctionName()
1875-
.GetName(Mangled::NamePreference::ePreferDemangledWithoutArguments)
1876-
.AsCString();
1877-
if (!name)
1878-
return false;
1879-
1880-
s.PutCString(name);
1881-
1882-
return true;
1891+
// Fallback to frame methods if available.
1892+
if (exe_ctx) {
1893+
StackFrame *frame = exe_ctx->GetFramePtr();
1894+
if (frame) {
1895+
const char *name = frame->GetFunctionName();
1896+
if (name) {
1897+
s.PutCString(name);
1898+
return true;
1899+
}
1900+
}
1901+
}
1902+
return false;
18831903
}
18841904

18851905
case Entry::Type::FunctionPrefix:
@@ -1906,13 +1926,26 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
19061926
}
19071927

19081928
case Entry::Type::FunctionNameWithArgs: {
1909-
if (!sc)
1910-
return false;
1929+
if (sc) {
1930+
if (FormatFunctionNameForLanguage(s, exe_ctx, sc))
1931+
return true;
19111932

1912-
if (FormatFunctionNameForLanguage(s, exe_ctx, sc))
1913-
return true;
1933+
if (HandleFunctionNameWithArgs(s, exe_ctx, *sc))
1934+
return true;
1935+
}
19141936

1915-
return HandleFunctionNameWithArgs(s, exe_ctx, *sc);
1937+
// Fallback to frame methods if available.
1938+
if (exe_ctx) {
1939+
StackFrame *frame = exe_ctx->GetFramePtr();
1940+
if (frame) {
1941+
const char *name = frame->GetDisplayFunctionName();
1942+
if (name) {
1943+
s.PutCString(name);
1944+
return true;
1945+
}
1946+
}
1947+
}
1948+
return false;
19161949
}
19171950
case Entry::Type::FunctionMangledName: {
19181951
if (!sc)
@@ -1954,12 +1987,11 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
19541987
case Entry::Type::FunctionPCOffset:
19551988
if (exe_ctx) {
19561989
StackFrame *frame = exe_ctx->GetFramePtr();
1957-
if (frame) {
1990+
if (frame)
19581991
if (DumpAddressOffsetFromFunction(s, sc, exe_ctx,
19591992
frame->GetFrameCodeAddress(), false,
19601993
false, false))
19611994
return true;
1962-
}
19631995
}
19641996
return false;
19651997

@@ -1983,11 +2015,8 @@ bool FormatEntity::Format(const Entry &entry, Stream &s,
19832015

19842016
case Entry::Type::LineEntryFile:
19852017
if (sc && sc->line_entry.IsValid()) {
1986-
Module *module = sc->module_sp.get();
1987-
if (module) {
1988-
if (DumpFile(s, sc->line_entry.GetFile(), (FileKind)entry.number))
1989-
return true;
1990-
}
2018+
if (DumpFile(s, sc->line_entry.GetFile(), (FileKind)entry.number))
2019+
return true;
19912020
}
19922021
return false;
19932022

0 commit comments

Comments
 (0)