Page MenuHomePhabricator

[lldb-vscode] Add Support for Module Event

Authored by aelitashen on Wed, Jun 24, 9:31 AM.



Whenever a module is created, removed or changed, lldb-vscode is now sending an event that can be interpreted by the IDE so that modules can be rendered in the IDE, like the tree view in this screenshot

Diff Detail

Unit TestsFailed

510 mswindows > Clang.CodeGen/arm-mve-intrinsics::dup.c
Script: -- : 'RUN: at line 2'; c:\ws\w5\llvm-project\premerge-checks\build\bin\clang.exe -cc1 -internal-isystem c:\ws\w5\llvm-project\premerge-checks\build\lib\clang\11.0.0\include -nostdsysteminc -triple thumbv8.1m.main-none-none-eabi -target-feature +mve.fp -mfloat-abi hard -fallow-half-arguments-and-returns -O0 -disable-O0-optnone -S -emit-llvm -o - C:\ws\w5\llvm-project\premerge-checks\clang\test\CodeGen\arm-mve-intrinsics\dup.c | c:\ws\w5\llvm-project\premerge-checks\build\bin\opt.exe -S -mem2reg -sroa -early-cse | c:\ws\w5\llvm-project\premerge-checks\build\bin\filecheck.exe C:\ws\w5\llvm-project\premerge-checks\clang\test\CodeGen\arm-mve-intrinsics\dup.c

Event Timeline

aelitashen created this revision.Wed, Jun 24, 9:31 AM
Herald added a project: Restricted Project. · View Herald TranscriptWed, Jun 24, 9:31 AM
wallace edited the summary of this revision. (Show Details)Wed, Jun 24, 9:53 AM
wallace added reviewers: kusmour, aadsm.
clayborg requested changes to this revision.Wed, Jun 24, 12:22 PM

So great first patch Yifan! A few things to fix up, see inlined comments.

We need to add a test for lldb::SBTarget::eBroadcastBitSymbolsLoaded if possible. This can be done by stripping "a.out" into "a.out.stripped" and then debugging "a.out.stripped" and then adding symbols using "target symbols add ..." to add the "a.out".


LLVM coding guidelines limit source lines to 80 characters. So just reformat as requested here.






remove empty line.


Need to add header documentation like the other functions in this file.


reformat per pre-merge checks


you check for "lldb::SBTarget::eBroadcastBitSymbolsLoaded" here, but didn't listen for that event in VSCode.cpp. Either remove lldb::SBTarget::eBroadcastBitSymbolsLoaded or add it to the events we want to listen for in VSCode.cpp


rename "solib_count" to "num_modules"?


Use for loop:

for (int i=0; i<num_modules; ++i) {
  auto module = lldb::SBTarget::GetModuleAtIndexFromEvent(i, event);
This revision now requires changes to proceed.Wed, Jun 24, 12:22 PM
labath added a subscriber: labath.Thu, Jun 25, 1:38 AM
labath added inline comments.

replace assertTrue(needle in haystack) with assertIn(needle, haystack)


You should use SBFileSpec::GetPath to get the file and dir components separated by the correct directory separator. (It's usage is somewhat clunky due to the SB API restrictions).

Formatting the codes

Herald added a project: Restricted Project. · View Herald TranscriptThu, Jun 25, 8:24 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
clayborg requested changes to this revision.Thu, Jun 25, 11:17 AM

We need to add a test for the symbols added target notification. See my previous comment on stripping a.out to a.out.stripped and then using "a.out.stripped" as the main executable.


We can probably simplify this to just be:

int main(int argc, char const *argv[]) {
  return 0; // breakpoint 1

Let LLDB take care of the directory delimiter. Otherwise this will be bad on windows:

char module_path[PATH_MAX];
module.GetFileSpec().GetPath(module_path, sizeof(module_path));

Let LLDB take care of the directory delimiter. Otherwise this will be bad on windows:

char symbol_path[PATH_MAX];
module.GetSymbolFileSpec().GetPath(module_path, sizeof(symbol_path));

We need to make sure the address returned is valid and we want the string value to be in hex. Are we sure std::to_string() will create a hex number? If not we can use sprintf:

uint64_t load_addr = module.GetObjectFileHeaderAddress().GetLoadAddress(;
if (load_addr != LLDB_INVALID_ADDRESS) {
  char load_addr_str[64];
  snprintf(load_addr_str, sizeof(load_addr_str), "0x%016" PRIx64, load_addr);
  object.try_emplace("addressRange", load_addr_str);

Might be better with text like:

/// Converts a LLDB module to a VS Code DAP module for use in "modules" events.
This revision now requires changes to proceed.Thu, Jun 25, 11:17 AM

Here is a makefile that does stripping:


Then when creating the target, use a.out.stripped:

exe = self.getBuildArtifact("a.out.stripped")
symbols = exe = self.getBuildArtifact("a.out")
target = self.dbg.CreateTarget(exe)

Then after you get the modules, you can do:

self.dbg.HandleCommand('target symbols add "%s"' % (symbols))

And that should trigger the symbols added notification and then you can fetch the modules again and verify that there is now a symbol file for "a.out.stripped".

aelitashen marked 3 inline comments as done.Tue, Jun 30, 2:52 PM
aelitashen added inline comments.

This piece of code will make path unreadable in the log, and cause the modules view cannot be displayed properly.


Same reason as above.


Decimal to Hex conversion is done in the IDE, not sure if we need to move it here.

Make LLDB take care of the directory delimiter

clayborg requested changes to this revision.Thu, Jul 2, 12:36 PM

See inline comments. Changes needed are:

  • test for eBroadcastBitSymbolsLoaded
  • add "version" to module info
  • test all data we expect in module info ('name', 'symbolFilePath', 'version', 'symbolStatus', 'addressRange')

We need to test eBroadcastBitSymbolsLoaded in this test. I would suggest we make an "a.out.stripped" (see the makefile form lldb/test/API/lang/objc/objc-ivar-stripped/Makefile for how to do this).


eBroadcastBitSymbolsLoaded needs to be tested: change this line to:

program_basename = 'a.out.stripped'
program = self.getBuildArtifact(program_basename)

after modifying the Makefile as suggested above.


Cached active modules, and use assertIn here and switch to "a.out.stripped", and verify the 'name' is in module info and that path is correct:

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('name', program_module, 'make sure 'path' key is in module')
self.assertEqual(program, program_module['name'])

use self.assertIn(...) and use the cached "active_modules" variable:

self.assertIn('symbolFilePath', program_module, 'Make sure 'symbolFilePath' key is in module info')
self.assertEqual(program, program_module['symbolFilePath'])

Then you need to verify all other information that you put into the Module like "symbolStatus" and "addressRange".


Now we would send a LLDB command line command to load the "a.out" symbols:

symbols = self.getBuildArtifact("a.out")
response = self.vscode.request_evaluate('`%s' % ('target symbols add -s "%s" "%s"' % (program, symbols)))

This will cause LLDB to load the symbol file "a.out" for the executable "a.out.stripped". This should cause the eBroadcastBitSymbolsLoaded notification to fire and the modules to get updated. Then you will get the active modules again and verify:

  • program is still "program" (the full path to the a.out.stripped binary)
  • 'symbolFilePath' is equal to our "symbols" variable from above (full path to "a.out")
  • 'symbolStatus' is now set to 'Symbols Loaded.'
  • 'addressRange' is still what we expect

Do we only want to try and add this "symbolFilePath" key if the path differs from "module_path"?


We should also fetch the version number from the module and populate the "version" key. To get the version number from a module you can use:

uint32_t version_nums[5];
const uint32_t num_versions = module.GetVersion(version_nums, sizeof(version_nums));
std::string version_str;
for (uint32_t i=0; i<num_versions; ++i) {
  if (!version_str.empty())
    version_str += ".";
  version_str += std::to_string(version_nums[i])
if (!version_str.empty()) 
  object.try_emplace("version", version_str);
This revision now requires changes to proceed.Thu, Jul 2, 12:36 PM

Add test for loading symbols, other module info and Add version to module info

clayborg requested changes to this revision.Tue, Jul 7, 12:31 PM

So looks like you didn't use "git commit --amend -a" again here. These changes are incremental changes on your patch which hasn't been submitted yet?


add a space after "program"


Do a similar check for ='path'

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'])

In general, make sure you test every key that you have added support for.


Check for the symbol status here:

self.assertEqual('Symbols not found.', program_module['symbolStatus'])

verify 'path' again


Add an else clause here:

} else {
  object.try_emplace("symbolStatus", "Symbols not found.");

fix indentation.


remove {} here for single line if statement

This revision now requires changes to proceed.Tue, Jul 7, 12:31 PM

Fix messy diff stack

clayborg requested changes to this revision.Tue, Jul 7, 5:31 PM

Just test for paths and this will be good to go!


add a check for the path:

self.assertEqual(program, program_module['path'])

check 'path' again here.


add a newline

This revision now requires changes to proceed.Tue, Jul 7, 5:31 PM

Add Path Verification in Test

clayborg accepted this revision.Wed, Jul 8, 10:20 AM

Looks good!

This revision is now accepted and ready to land.Wed, Jul 8, 10:20 AM