Add Debug Info Size to Symbol Status

If a module has debug info, the size of debug symbol will be displayed after the Symbols Loaded Message for each module in the VScode modules view.{F12335461}

Reviewed By: wallace, clayborg

Differential Revision: https://reviews.llvm.org/D83731
This commit is contained in:
Yifan Shen 2020-07-24 13:30:04 -07:00 committed by Walter Erquinigo
parent 313b60742a
commit 2c1bea88a5
4 changed files with 121 additions and 26 deletions

View File

@ -53,11 +53,12 @@ class VSCodeTestCaseBase(TestBase):
breakpoint_ids.append('%i' % (breakpoint['id']))
return breakpoint_ids
def waitUntil(self, condition):
while True:
if condition():
break
def waitUntil(self, condition_callback):
for _ in range(20):
if condition_callback():
return True
time.sleep(0.5)
return False
def verify_breakpoint_hit(self, breakpoint_ids):
'''Wait for the process we are debugging to stop, and verify we hit

View File

@ -2,12 +2,16 @@ DYLIB_NAME := foo
DYLIB_CXX_SOURCES := foo.cpp
CXX_SOURCES := main.cpp
all: a.out.stripped
LD_EXTRAS := -Wl,-rpath "-Wl,$(shell pwd)"
USE_LIBDL :=1
include Makefile.rules
a.out.stripped: a.out.dSYM
all: a.out.stripped
a.out.stripped:
strip -o a.out.stripped a.out
ifneq "$(CODESIGN)" ""
$(CODESIGN) -fs - a.out.stripped
endif
endif

View File

@ -10,56 +10,93 @@ from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
import lldbvscode_testcase
import re
class TestVSCode_module(lldbvscode_testcase.VSCodeTestCaseBase):
mydir = TestBase.compute_mydir(__file__)
@skipIfWindows
@skipUnlessDarwin
@skipIfRemote
def test_modules_event(self):
def run_test(self, symbol_basename, expect_debug_info_size):
program_basename = "a.out.stripped"
program= self.getBuildArtifact(program_basename)
program = self.getBuildArtifact(program_basename)
self.build_and_launch(program)
functions = ['foo']
breakpoint_ids = self.set_function_breakpoints(functions)
self.assertEquals(len(breakpoint_ids), len(functions),
'expect one breakpoint')
self.assertEquals(len(breakpoint_ids), len(functions), 'expect one breakpoint')
self.continue_to_breakpoints(breakpoint_ids)
active_modules = self.vscode.get_active_modules()
self.assertIn(program_basename, active_modules, '%s module is in active modules' % (program_basename))
program_module = active_modules[program_basename]
self.assertIn(program_basename, active_modules, '%s module is in active modules' % (program_basename))
self.assertIn('name', program_module, 'make sure name is in module')
self.assertEqual(program_basename, program_module['name'])
self.assertIn('path', program_module, 'make sure path is in module')
self.assertEqual(program, program_module['path'])
self.assertTrue('symbolFilePath' not in program_module, 'Make sure a.out.stripped has no debug info')
self.assertEqual('Symbols not found.', program_module['symbolStatus'])
symbol_path = self.getBuildArtifact("a.out")
self.vscode.request_evaluate('`%s' % ('target symbols add -s "%s" "%s"' % (program, symbol_path)))
symbols_path = self.getBuildArtifact(symbol_basename)
self.vscode.request_evaluate('`%s' % ('target symbols add -s "%s" "%s"' % (program, symbols_path)))
def checkSymbolsLoaded():
active_modules = self.vscode.get_active_modules()
program_module = active_modules[program_basename]
return 'Symbols loaded.' == program_module['symbolStatus']
self.waitUntil(checkSymbolsLoaded)
def checkSymbolsLoadedWithSize():
active_modules = self.vscode.get_active_modules()
program_module = active_modules[program_basename]
symbolsStatus = program_module['symbolStatus']
symbol_regex = re.compile(r"Symbols loaded. \([0-9]+(\.[0-9]*)?[KMG]?B\)")
return symbol_regex.match(program_module['symbolStatus'])
if expect_debug_info_size:
self.waitUntil(checkSymbolsLoadedWithSize)
else:
self.waitUntil(checkSymbolsLoaded)
active_modules = self.vscode.get_active_modules()
program_module = active_modules[program_basename]
self.assertEqual(program_basename, program_module['name'])
self.assertEqual(program, program_module['path'])
self.assertEqual('Symbols loaded.', program_module['symbolStatus'])
self.assertIn('symbolFilePath', program_module)
self.assertEqual(symbol_path, program_module['symbolFilePath'])
self.assertIn(symbols_path, program_module['symbolFilePath'])
self.assertIn('addressRange', program_module)
@skipIfWindows
@skipUnlessDarwin
@skipIfRemote
#TODO: Update the Makefile so that this test runs on Linux
def test_module_event(self):
'''
Mac or linux.
On mac, if we load a.out as our symbol file, we will use DWARF with .o files and we will
have debug symbols, but we won't see any debug info size because all of the DWARF
sections are in .o files.
On other platforms, we expect a.out to have debug info, so we will expect a size.
expect_debug_info_size = platform.system() != 'Darwin'
return self.run_test("a.out", expect_debug_info_size)
'''
expect_debug_info_size = platform.system() != 'Darwin'
return self.run_test("a.out", expect_debug_info_size)
@skipIfWindows
@skipUnlessDarwin
@skipIfRemote
def test_module_event_dsym(self):
'''
Darwin only test with dSYM file.
On mac, if we load a.out.dSYM as our symbol file, we will have debug symbols and we
will have DWARF sections added to the module, so we will expect a size.
return self.run_test("a.out.dSYM", True)
'''
return self.run_test("a.out.dSYM", True)
@skipIfWindows
@skipUnlessDarwin
@skipIfRemote
def test_compile_units(self):
program= self.getBuildArtifact("a.out")
program = self.getBuildArtifact("a.out")
self.build_and_launch(program)
source = "main.cpp"
main_source_path = self.getSourcePath(source)

View File

@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include <algorithm>
#include <iomanip>
#include <sstream>
#include "llvm/ADT/Optional.h"
#include "llvm/Support/FormatAdapters.h"
@ -327,6 +329,50 @@ llvm::json::Value CreateBreakpoint(lldb::SBBreakpoint &bp,
return llvm::json::Value(std::move(object));
}
static uint64_t GetDebugInfoSizeInSection(lldb::SBSection section) {
uint64_t debug_info_size = 0;
llvm::StringRef section_name(section.GetName());
if (section_name.startswith(".debug") || section_name.startswith("__debug") ||
section_name.startswith(".apple") || section_name.startswith("__apple"))
debug_info_size += section.GetFileByteSize();
size_t num_sub_sections = section.GetNumSubSections();
for (size_t i = 0; i < num_sub_sections; i++) {
debug_info_size +=
GetDebugInfoSizeInSection(section.GetSubSectionAtIndex(i));
}
return debug_info_size;
}
static uint64_t GetDebugInfoSize(lldb::SBModule module) {
uint64_t debug_info_size = 0;
size_t num_sections = module.GetNumSections();
for (size_t i = 0; i < num_sections; i++) {
debug_info_size += GetDebugInfoSizeInSection(module.GetSectionAtIndex(i));
}
return debug_info_size;
}
static std::string ConvertDebugInfoSizeToString(uint64_t debug_info) {
std::ostringstream oss;
oss << " (";
oss << std::fixed << std::setprecision(1);
if (debug_info < 1024) {
oss << debug_info << "B";
} else if (debug_info < 1024 * 1024) {
double kb = double(debug_info) / 1024.0;
oss << kb << "KB";
} else if (debug_info < 1024 * 1024 * 1024) {
double mb = double(debug_info) / (1024.0 * 1024.0);
oss << mb << "MB";
} else {
double gb = double(debug_info) / (1024.0 * 1024.0 * 1024.0);
oss << gb << "GB";
;
}
oss << ")";
return oss.str();
}
llvm::json::Value CreateModule(lldb::SBModule &module) {
llvm::json::Object object;
if (!module.IsValid())
@ -339,9 +385,15 @@ llvm::json::Value CreateModule(lldb::SBModule &module) {
std::string module_path(module_path_arr);
object.try_emplace("path", module_path);
if (module.GetNumCompileUnits() > 0) {
object.try_emplace("symbolStatus", "Symbols loaded.");
std::string symbol_str = "Symbols loaded.";
uint64_t debug_info = GetDebugInfoSize(module);
if (debug_info > 0) {
symbol_str += ConvertDebugInfoSizeToString(debug_info);
}
object.try_emplace("symbolStatus", symbol_str);
char symbol_path_arr[PATH_MAX];
module.GetSymbolFileSpec().GetPath(symbol_path_arr, sizeof(symbol_path_arr));
module.GetSymbolFileSpec().GetPath(symbol_path_arr,
sizeof(symbol_path_arr));
std::string symbol_path(symbol_path_arr);
object.try_emplace("symbolFilePath", symbol_path);
} else {
@ -352,8 +404,9 @@ llvm::json::Value CreateModule(lldb::SBModule &module) {
object.try_emplace("addressRange", loaded_addr);
std::string version_str;
uint32_t version_nums[3];
uint32_t num_versions = module.GetVersion(version_nums, sizeof(version_nums)/sizeof(uint32_t));
for (uint32_t i=0; i<num_versions; ++i) {
uint32_t num_versions =
module.GetVersion(version_nums, sizeof(version_nums) / sizeof(uint32_t));
for (uint32_t i = 0; i < num_versions; ++i) {
if (!version_str.empty())
version_str += ".";
version_str += std::to_string(version_nums[i]);