-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[lldb] Load embedded type summary section (#7859) (#8040) #113743
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ | |
#include "lldb/Core/StructuredDataImpl.h" | ||
#include "lldb/Core/ValueObject.h" | ||
#include "lldb/Core/ValueObjectConstResult.h" | ||
#include "lldb/DataFormatters/DataVisualization.h" | ||
#include "lldb/Expression/DiagnosticManager.h" | ||
#include "lldb/Expression/ExpressionVariable.h" | ||
#include "lldb/Expression/REPL.h" | ||
|
@@ -1537,6 +1538,76 @@ static void LoadScriptingResourceForModule(const ModuleSP &module_sp, | |
feedback_stream.GetData()); | ||
} | ||
|
||
// Load type summaries embedded in the binary. These are type summaries provided | ||
// by the authors of the code. | ||
static void LoadTypeSummariesForModule(ModuleSP module_sp) { | ||
auto *sections = module_sp->GetSectionList(); | ||
if (!sections) | ||
return; | ||
|
||
auto summaries_sp = | ||
sections->FindSectionByType(eSectionTypeLLDBTypeSummaries, true); | ||
if (!summaries_sp) | ||
return; | ||
|
||
Log *log = GetLog(LLDBLog::DataFormatters); | ||
const char *module_name = module_sp->GetObjectName().GetCString(); | ||
|
||
TypeCategoryImplSP category; | ||
DataVisualization::Categories::GetCategory(ConstString("default"), category); | ||
|
||
// The type summary record is serialized as follows. | ||
// | ||
// Each record contains, in order: | ||
// * Version number of the record format | ||
// * The remaining size of the record | ||
// * The size of the type identifier | ||
// * The type identifier, either a type name, or a regex | ||
// * The size of the summary string | ||
// * The summary string | ||
// | ||
// Integers are encoded using ULEB. | ||
// | ||
// Strings are encoded with first a length (ULEB), then the string contents, | ||
// and lastly a null terminator. The length includes the null. | ||
|
||
DataExtractor extractor; | ||
auto section_size = summaries_sp->GetSectionData(extractor); | ||
lldb::offset_t offset = 0; | ||
while (offset < section_size) { | ||
uint64_t version = extractor.GetULEB128(&offset); | ||
uint64_t record_size = extractor.GetULEB128(&offset); | ||
if (version == 1) { | ||
uint64_t type_size = extractor.GetULEB128(&offset); | ||
llvm::StringRef type_name = extractor.GetCStr(&offset, type_size); | ||
uint64_t summary_size = extractor.GetULEB128(&offset); | ||
llvm::StringRef summary_string = extractor.GetCStr(&offset, summary_size); | ||
if (!type_name.empty() && !summary_string.empty()) { | ||
TypeSummaryImpl::Flags flags; | ||
auto summary_sp = | ||
std::make_shared<StringSummaryFormat>(flags, summary_string.data()); | ||
FormatterMatchType match_type = eFormatterMatchExact; | ||
if (summary_string.front() == '^' && summary_string.back() == '$') | ||
match_type = eFormatterMatchRegex; | ||
category->AddTypeSummary(type_name, match_type, summary_sp); | ||
LLDB_LOGF(log, "Loaded embedded type summary for '%s' from %s.", | ||
type_name.data(), module_name); | ||
} else { | ||
if (type_name.empty()) | ||
LLDB_LOGF(log, "Missing string(s) in embedded type summary in %s.", | ||
module_name); | ||
} | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could Also you could |
||
// Skip unsupported record. | ||
offset += record_size; | ||
LLDB_LOGF( | ||
log, | ||
"Skipping unsupported embedded type summary of version %llu in %s.", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the |
||
version, module_name); | ||
} | ||
} | ||
} | ||
|
||
void Target::ClearModules(bool delete_locations) { | ||
ModulesDidUnload(m_images, delete_locations); | ||
m_section_load_history.Clear(); | ||
|
@@ -1775,6 +1846,7 @@ void Target::ModulesDidLoad(ModuleList &module_list) { | |
for (size_t idx = 0; idx < num_images; ++idx) { | ||
ModuleSP module_sp(module_list.GetModuleAtIndex(idx)); | ||
LoadScriptingResourceForModule(module_sp, this); | ||
LoadTypeSummariesForModule(module_sp); | ||
} | ||
m_breakpoint_list.UpdateBreakpoints(module_list, true, false); | ||
m_internal_breakpoint_list.UpdateBreakpoints(module_list, true, false); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
C_SOURCES := main.c | ||
include Makefile.rules |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import lldb | ||
from lldbsuite.test.decorators import * | ||
from lldbsuite.test.lldbtest import * | ||
from lldbsuite.test import lldbutil | ||
|
||
|
||
class TestCase(TestBase): | ||
@skipUnlessDarwin | ||
def test(self): | ||
self.build() | ||
lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c")) | ||
self.expect("v player", substrs=['"Dirk" (41)']) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#include <stdio.h> | ||
|
||
struct Player { | ||
char *name; | ||
int number; | ||
}; | ||
|
||
__attribute__((used, section("__DATA_CONST,__lldbsummaries"))) unsigned char | ||
_Player_type_summary[] = "\x01" // version | ||
"\x25" // record size | ||
"\x07" // type name size | ||
"Player\0" // type name | ||
"\x1c" // summary string size | ||
"${var.name} (${var.number})"; // summary string | ||
|
||
int main() { | ||
struct Player player; | ||
player.name = "Dirk"; | ||
player.number = 41; | ||
puts("break here"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this actually show up in the logs? If so |
||
return 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this log message always be printed? It looks like you have to have both strings so if you get to the else, one of them is empty. This will only log if one of them is empty but not the other one.
Might as well put in what strings they are too. "Missing type or summary string in....".