This is an archive of the discontinued LLVM Phabricator instance.

[lldb-vscode] Add Support for Module Event
ClosedPublic

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

Details

Summary

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

Event Timeline

aelitashen created this revision.Jun 24 2020, 9:31 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 24 2020, 9:31 AM
wallace edited the summary of this revision. (Show Details)Jun 24 2020, 9:53 AM
wallace added reviewers: kusmour, aadsm.
clayborg requested changes to this revision.Jun 24 2020, 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".

lldb/tools/lldb-vscode/JSONUtils.cpp
335

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

340

Ditto

343

Ditto

346

remove empty line.

lldb/tools/lldb-vscode/JSONUtils.h
241

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

lldb/tools/lldb-vscode/VSCode.cpp
357–359

reformat per pre-merge checks

lldb/tools/lldb-vscode/lldb-vscode.cpp
440

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

441

rename "solib_count" to "num_modules"?

442–445

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.Jun 24 2020, 12:22 PM
labath added a subscriber: labath.Jun 25 2020, 1:38 AM
labath added inline comments.
lldb/test/API/tools/lldb-vscode/module/TestVSCode_module.py
28–30

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

lldb/tools/lldb-vscode/JSONUtils.cpp
336

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 TranscriptJun 25 2020, 8:24 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
clayborg requested changes to this revision.Jun 25 2020, 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.

lldb/test/API/tools/lldb-vscode/module/main.cpp
2–9

We can probably simplify this to just be:

int main(int argc, char const *argv[]) {
  return 0; // breakpoint 1
}
lldb/tools/lldb-vscode/JSONUtils.cpp
337–340

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));
344–346

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));
349–350

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(g_vsc.target);
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);
}
lldb/tools/lldb-vscode/JSONUtils.h
241

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.Jun 25 2020, 11:17 AM

Here is a makefile that does stripping:

llvm-project/lldb/test/API/lang/objc/objc-ivar-stripped/Makefile

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.Jun 30 2020, 2:52 PM
aelitashen added inline comments.
lldb/tools/lldb-vscode/JSONUtils.cpp
337–340

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

344–346

Same reason as above.

349–350

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.Jul 2 2020, 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')
lldb/test/API/tools/lldb-vscode/module/Makefile
4

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).

lldb/test/API/tools/lldb-vscode/module/TestVSCode_module.py
21

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.

28

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'])
30–31

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".

30–31

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
lldb/tools/lldb-vscode/JSONUtils.cpp
344–345

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

351

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.Jul 2 2020, 12:36 PM

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

clayborg requested changes to this revision.Jul 7 2020, 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?

lldb/test/API/tools/lldb-vscode/module/TestVSCode_module.py
21

add a space after "program"

33–34

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.

35

Check for the symbol status here:

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

verify 'path' again

lldb/tools/lldb-vscode/JSONUtils.cpp
329–355

Add an else clause here:

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

fix indentation.

337–339

remove {} here for single line if statement

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

Fix messy diff stack

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

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

lldb/test/API/tools/lldb-vscode/module/TestVSCode_module.py
31

add a newline

36

add a check for the path:

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

check 'path' again here.

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

Add Path Verification in Test

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

Looks good!

This revision is now accepted and ready to land.Jul 8 2020, 10:20 AM
This revision was automatically updated to reflect the committed changes.

Hi, your git commit contains extra Phabricator tags. You can drop Reviewers: Subscribers: Tags: and the text Summary: from the git commit with the following script:

arcfilter () {
        arc amend
        git log -1 --pretty=%B | awk '/Reviewers:|Subscribers:/{p=1} /Reviewed By:|Differential Revision:/{p=0} !p && !/^Summary:$/ {sub(/^Summary: /,"");print}' | git commit --amend --date=now -F -
}

Reviewed By: is considered important by some people. Please keep the tag. (--date=now is my personal preference (author dates are usually not useful. Using committer dates can make log almost monotonic in time))

llvm/utils/git/pre-push.py can validate the message does not include unneeded tags.

Hi, your git commit contains extra Phabricator tags. You can drop Reviewers: Subscribers: Tags: and the text Summary: from the git commit with the following script:

arcfilter () {
        arc amend
        git log -1 --pretty=%B | awk '/Reviewers:|Subscribers:/{p=1} /Reviewed By:|Differential Revision:/{p=0} !p && !/^Summary:$/ {sub(/^Summary: /,"");print}' | git commit --amend --date=now -F -
}

Reviewed By: is considered important by some people. Please keep the tag. (--date=now is my personal preference (author dates are usually not useful. Using committer dates can make log almost monotonic in time))

llvm/utils/git/pre-push.py can validate the message does not include unneeded tags.

Can we modify this script to remove the unneeded tags instead of detecting it?

Hi, your git commit contains extra Phabricator tags. You can drop Reviewers: Subscribers: Tags: and the text Summary: from the git commit with the following script:

arcfilter () {
        arc amend
        git log -1 --pretty=%B | awk '/Reviewers:|Subscribers:/{p=1} /Reviewed By:|Differential Revision:/{p=0} !p && !/^Summary:$/ {sub(/^Summary: /,"");print}' | git commit --amend --date=now -F -
}

Reviewed By: is considered important by some people. Please keep the tag. (--date=now is my personal preference (author dates are usually not useful. Using committer dates can make log almost monotonic in time))

llvm/utils/git/pre-push.py can validate the message does not include unneeded tags.

Can we modify this script to remove the unneeded tags instead of detecting it?

@mehdi_amini ^^