-
Notifications
You must be signed in to change notification settings - Fork 133
fix: fixing exception on heap dump analysis on Windows #1495
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 |
|---|---|---|
| @@ -1,12 +1,15 @@ | ||
| /******************************************************************************* | ||
| * Copyright 2021 Espressif Systems (Shanghai) PTE LTD. All rights reserved. | ||
| * Copyright 2021-2026 Espressif Systems (Shanghai) PTE LTD. All rights reserved. | ||
| * Use is subject to license terms. | ||
| *******************************************************************************/ | ||
| package com.espressif.idf.ui.handlers; | ||
|
|
||
| import java.io.File; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.regex.Matcher; | ||
| import java.util.regex.Pattern; | ||
|
|
||
| import org.eclipse.core.commands.AbstractHandler; | ||
| import org.eclipse.core.commands.ExecutionEvent; | ||
|
|
@@ -41,6 +44,8 @@ | |
| */ | ||
| public class HeapDumpAnalysisHandler extends AbstractHandler | ||
| { | ||
| private static final Pattern CORE_SUFFIX = Pattern.compile("(?i)^(.+\\.svdat)_core\\d+$"); //$NON-NLS-1$ | ||
| private static final String FILE_URL_PREFIX = "file://"; //$NON-NLS-1$ | ||
|
|
||
| @Override | ||
| public Object execute(ExecutionEvent event) throws ExecutionException | ||
|
|
@@ -52,37 +57,91 @@ public Object execute(ExecutionEvent event) throws ExecutionException | |
| messageConsoleStream.println("App Context Null"); //$NON-NLS-1$ | ||
| return null; | ||
| } | ||
|
|
||
| // get the selected dumpFile | ||
|
|
||
| IResource dumpFile = EclipseHandler.getSelectedResource((IEvaluationContext) event.getApplicationContext()); | ||
| IProject selectedProject = dumpFile.getProject(); | ||
| IFile elfSymbolsFile = selectedProject.getFolder("build").getFile(selectedProject.getName().concat(".elf")); //$NON-NLS-1$ //$NON-NLS-2$ | ||
|
|
||
| List<String> commands = new ArrayList<String>(); | ||
| List<String> commands = new ArrayList<>(); | ||
| commands.add(IDFUtil.getIDFPythonEnvPath()); | ||
| commands.add(IDFUtil.getIDFSysviewTraceScriptFile().getAbsolutePath()); | ||
| commands.add("-j"); //$NON-NLS-1$ | ||
| commands.add("-b"); //$NON-NLS-1$ | ||
| commands.add(elfSymbolsFile.getRawLocation().toOSString()); | ||
| commands.add("file://".concat(dumpFile.getRawLocation().toString())); //$NON-NLS-1$ | ||
| commands.addAll(resolveTraceSources(dumpFile)); | ||
|
|
||
| messageConsoleStream.println("Commands Prepared"); //$NON-NLS-1$ | ||
| for (String command : commands) | ||
| { | ||
| messageConsoleStream.print(command); | ||
| messageConsoleStream.print(" "); //$NON-NLS-1$ | ||
| } | ||
|
|
||
| Map<String, String> envMap = new IDFEnvironmentVariables().getSystemEnvMap(); | ||
| Path pathToProject = new Path(selectedProject.getLocation().toString()); | ||
| String jsonOutput = runCommand(commands, pathToProject, envMap); | ||
| FileUtil.writeFile(selectedProject, "build/dump.json", jsonOutput, false); //$NON-NLS-1$ | ||
| messageConsoleStream.println(); | ||
| messageConsoleStream.println(jsonOutput); | ||
|
|
||
| if (!isJsonOutput(jsonOutput)) | ||
| { | ||
| Logger.log("Heap dump analysis failed; skipping editor launch"); //$NON-NLS-1$ | ||
| return null; | ||
| } | ||
|
|
||
| FileUtil.writeFile(selectedProject, "build/dump.json", jsonOutput, false); //$NON-NLS-1$ | ||
| launchEditor(selectedProject.getFile("build/dump.json")); //$NON-NLS-1$ | ||
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * Prefer OpenOCD per-core dumps ({@code *.svdat_core0}, {@code *_core1}, …) when present. Passing those with a | ||
| * {@code file://} URL avoids the Windows multicore-split bug in {@code sysviewtrace_proc.py}. Falls back to the | ||
| * selected file when no core siblings exist. | ||
| */ | ||
| static List<String> resolveTraceSources(IResource dumpFile) | ||
| { | ||
| File selected = dumpFile.getRawLocation().toFile(); | ||
| File directory = selected.getParentFile(); | ||
| String baseName = stripCoreSuffix(selected.getName()); | ||
|
|
||
| List<String> coreSources = new ArrayList<>(); | ||
| for (int core = 0;; core++) | ||
| { | ||
| File coreFile = new File(directory, baseName + "_core" + core); //$NON-NLS-1$ | ||
| if (!coreFile.isFile()) | ||
| { | ||
| break; | ||
| } | ||
| coreSources.add(toFileUrl(coreFile)); | ||
| } | ||
|
|
||
| if (!coreSources.isEmpty()) | ||
| { | ||
| return coreSources; | ||
| } | ||
|
|
||
| List<String> single = new ArrayList<>(1); | ||
| single.add(toFileUrl(selected)); | ||
| return single; | ||
| } | ||
|
|
||
| private static String stripCoreSuffix(String fileName) | ||
| { | ||
| Matcher matcher = CORE_SUFFIX.matcher(fileName); | ||
| return matcher.matches() ? matcher.group(1) : fileName; | ||
| } | ||
|
|
||
| private static String toFileUrl(File file) | ||
| { | ||
| return FILE_URL_PREFIX + file.getAbsolutePath().replace('\\', '/'); | ||
| } | ||
|
|
||
| private static boolean isJsonOutput(String output) | ||
| { | ||
| return output != null && output.trim().startsWith("{"); //$NON-NLS-1$ | ||
|
Comment on lines
+140
to
+142
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. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Parse the complete output before writing Line 142 accepts malformed output such as 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| private void launchEditor(IFile jsonDumpFile) | ||
| { | ||
| FileEditorInput editorInput = new FileEditorInput(jsonDumpFile); | ||
|
|
@@ -117,7 +176,6 @@ private String runCommand(List<String> arguments, Path workDir, Map<String, Stri | |
| return IDFCorePlugin.errorStatus("Status can't be null", null).toString(); //$NON-NLS-1$ | ||
| } | ||
|
|
||
| // process export command output | ||
| exportCmdOp = status.getMessage(); | ||
| Logger.log(exportCmdOp); | ||
| } | ||
|
|
||
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.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: espressif/idf-eclipse-plugin
Length of output: 218
🏁 Script executed:
Repository: espressif/idf-eclipse-plugin
Length of output: 8081
🏁 Script executed:
Repository: espressif/idf-eclipse-plugin
Length of output: 50384
Serialize the trace path with a standard file-URI API.
toFileUrl()builds rawfile://strings, so Windows paths likefile://C:/...putC:in the URI authority, and URI-reserved characters such as#,?,%, or spaces split the path incorrectly.sysviewtrace_proc.pyreceives the wrong trace argument and can fail conversion. UseFile.toURI().toASCIIString()or an equivalent API to serialize the path.Also applies to:
bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/handlers/HeapDumpAnalysisHandler.java:135-137🤖 Prompt for AI Agents