Skip to content

Complete the Implementation of DAP modules explorer. #139934

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

Merged
merged 4 commits into from
May 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions lldb/tools/lldb-dap/JSONUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -416,9 +416,11 @@ llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module,
} else {
object.try_emplace("symbolStatus", "Symbols not found.");
}
std::string loaded_addr = std::to_string(
module.GetObjectFileHeaderAddress().GetLoadAddress(target));
object.try_emplace("addressRange", loaded_addr);
std::string load_address =
llvm::formatv("{0:x}",
module.GetObjectFileHeaderAddress().GetLoadAddress(target))
.str();
object.try_emplace("addressRange", load_address);
std::string version_str;
uint32_t version_nums[3];
uint32_t num_versions =
Expand Down
20 changes: 20 additions & 0 deletions lldb/tools/lldb-dap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,26 @@
}
}
],
"commands": [
{
"command": "lldb-dap.modules.copyProperty",
"title": "Copy Value"
}
],
"menus": {
"commandPalette": [
{
"command": "lldb-dap.modules.copyProperty",
"when": "false"
}
],
"view/item/context": [
{
"command": "lldb-dap.modules.copyProperty",
"when": "view == lldb-dap.modules && viewItem == property"
}
]
},
"breakpoints": [
{
"language": "ada"
Expand Down
10 changes: 9 additions & 1 deletion lldb/tools/lldb-dap/src-ts/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import { LaunchUriHandler } from "./uri-launch-handler";
import { LLDBDapConfigurationProvider } from "./debug-configuration-provider";
import { LLDBDapServer } from "./lldb-dap-server";
import { DebugSessionTracker } from "./debug-session-tracker";
import { ModulesDataProvider } from "./ui/modules-data-provider";
import {
ModulesDataProvider,
ModuleProperty,
} from "./ui/modules-data-provider";

/**
* This class represents the extension and manages its life cycle. Other extensions
Expand Down Expand Up @@ -40,6 +43,11 @@ export class LLDBDapExtension extends DisposableContext {
),
vscode.window.registerUriHandler(new LaunchUriHandler()),
);

vscode.commands.registerCommand(
"lldb-dap.modules.copyProperty",
(node: ModuleProperty) => vscode.env.clipboard.writeText(node.value),
);
}
}

Expand Down
98 changes: 62 additions & 36 deletions lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,86 @@ import * as vscode from "vscode";
import { DebugProtocol } from "@vscode/debugprotocol";
import { DebugSessionTracker } from "../debug-session-tracker";

/** A tree data provider for listing loaded modules for the active debug session. */
export class ModulesDataProvider
implements vscode.TreeDataProvider<DebugProtocol.Module>
{
private changeTreeData = new vscode.EventEmitter<void>();
readonly onDidChangeTreeData = this.changeTreeData.event;
export interface ModuleProperty {
key: string;
value: string;
}

constructor(private readonly tracker: DebugSessionTracker) {
tracker.onDidChangeModules(() => this.changeTreeData.fire());
vscode.debug.onDidChangeActiveDebugSession(() =>
this.changeTreeData.fire(),
);
/** Type to represent both Module and ModuleProperty since TreeDataProvider
* expects one concrete type */
type TreeData = DebugProtocol.Module | ModuleProperty;

function isModule(type: TreeData): type is DebugProtocol.Module {
return (type as DebugProtocol.Module).id !== undefined;
}

class ModuleItem extends vscode.TreeItem {
constructor(module: DebugProtocol.Module) {
super(module.name, vscode.TreeItemCollapsibleState.Collapsed);
this.description = module.symbolStatus;
}

getTreeItem(module: DebugProtocol.Module): vscode.TreeItem {
let treeItem = new vscode.TreeItem(/*label=*/ module.name);
if (module.path) {
treeItem.description = `${module.id} -- ${module.path}`;
} else {
treeItem.description = `${module.id}`;
}
static getProperties(module: DebugProtocol.Module): ModuleProperty[] {
// does not include the name and symbol status as it is show in the parent.
let children: ModuleProperty[] = [];
children.push({ key: "id:", value: module.id.toString() });

const tooltip = new vscode.MarkdownString();
tooltip.appendMarkdown(`# ${module.name}\n\n`);
tooltip.appendMarkdown(`- **ID**: ${module.id}\n`);
if (module.addressRange) {
tooltip.appendMarkdown(
`- **Load address**: 0x${Number(module.addressRange).toString(16)}\n`,
);
children.push({
key: "load address:",
value: module.addressRange,
});
}
if (module.path) {
tooltip.appendMarkdown(`- **Path**: ${module.path}\n`);
children.push({ key: "path:", value: module.path });
}
if (module.version) {
tooltip.appendMarkdown(`- **Version**: ${module.version}\n`);
}
if (module.symbolStatus) {
tooltip.appendMarkdown(`- **Symbol status**: ${module.symbolStatus}\n`);
children.push({ key: "version:", value: module.version });
}
if (module.symbolFilePath) {
tooltip.appendMarkdown(
`- **Symbol file path**: ${module.symbolFilePath}\n`,
);
children.push({ key: "symbol filepath:", value: module.symbolFilePath });
}
return children;
}
}

/** A tree data provider for listing loaded modules for the active debug session. */
export class ModulesDataProvider implements vscode.TreeDataProvider<TreeData> {
private changeTreeData = new vscode.EventEmitter<void>();
readonly onDidChangeTreeData = this.changeTreeData.event;

constructor(private readonly tracker: DebugSessionTracker) {
tracker.onDidChangeModules(() => this.changeTreeData.fire());
vscode.debug.onDidChangeActiveDebugSession(() =>
this.changeTreeData.fire(),
);
}

getTreeItem(module: TreeData): vscode.TreeItem {
if (isModule(module)) {
return new ModuleItem(module);
}

treeItem.tooltip = tooltip;
return treeItem;
let item = new vscode.TreeItem(module.key);
item.description = module.value;
item.tooltip = `${module.key} ${module.value}`;
item.contextValue = "property";
return item;
}

getChildren(): DebugProtocol.Module[] {
getChildren(element?: TreeData): TreeData[] {
if (!vscode.debug.activeDebugSession) {
return [];
}

return this.tracker.debugSessionModules(vscode.debug.activeDebugSession);
if (!element) {
return this.tracker.debugSessionModules(vscode.debug.activeDebugSession);
}

if (isModule(element)) {
return ModuleItem.getProperties(element);
}

return [];
}
}
Loading