Skip to content

Commit

Permalink
Improvements to crash call stack logging. (#12247)
Browse files Browse the repository at this point in the history
* Updates to crash call stack logging.
* Move crash logging to its own channel.
  • Loading branch information
sean-mcmanus committed Apr 30, 2024
1 parent efdc8e9 commit 0ef77b5
Showing 2 changed files with 42 additions and 16 deletions.
47 changes: 31 additions & 16 deletions Extension/src/LanguageServer/extension.ts
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ import { TargetPopulation } from 'vscode-tas-client';
import * as which from 'which';
import { logAndReturn } from '../Utility/Async/returns';
import * as util from '../common';
import { getCrashCallStacksChannel } from '../logger';
import { PlatformInformation } from '../platform';
import * as telemetry from '../telemetry';
import { Client, DefaultClient, DoxygenCodeActionCommandArguments, openFileVersions } from './client';
@@ -38,6 +39,7 @@ export const configPrefix: string = "C/C++: ";

let prevMacCrashFile: string;
let prevCppCrashFile: string;
let prevCppCrashCallStackData: string = "";
export let clients: ClientCollection;
let activeDocument: vscode.TextDocument | undefined;
let ui: LanguageStatusUI;
@@ -988,10 +990,12 @@ export function watchForCrashes(crashDirectory: string): void {
if (!filename.startsWith("cpptools")) {
return;
}
const crashDate: Date = new Date();

// Wait 5 seconds to allow time for the crash log to finish being written.
setTimeout(() => {
fs.readFile(path.resolve(crashDirectory, filename), 'utf8', (err, data) => {
void handleCrashFileRead(crashDirectory, filename, err, data);
void handleCrashFileRead(crashDirectory, filename, crashDate, err, data);
});
}, 5000);
});
@@ -1116,7 +1120,7 @@ function handleMacCrashFileRead(err: NodeJS.ErrnoException | undefined | null, d
logMacCrashTelemetry(data);
}

async function handleCrashFileRead(crashDirectory: string, crashFile: string, err: NodeJS.ErrnoException | undefined | null, data: string): Promise<void> {
async function handleCrashFileRead(crashDirectory: string, crashFile: string, crashDate: Date, err: NodeJS.ErrnoException | undefined | null, data: string): Promise<void> {
if (err) {
if (err.code === "ENOENT") {
return; // ignore known issue
@@ -1126,23 +1130,23 @@ async function handleCrashFileRead(crashDirectory: string, crashFile: string, er

const lines: string[] = data.split("\n");
let addressData: string = ".\n.";
data = (crashFile.startsWith("cpptools-srv") ? "cpptools-srv.txt" : crashFile) + "\n";
const isCppToolsSrv: boolean = crashFile.startsWith("cpptools-srv");
const telemetryHeader: string = (isCppToolsSrv ? "cpptools-srv.txt" : crashFile) + "\n";
const filtPath: string | null = which.sync("c++filt", { nothrow: true });
const isMac: boolean = process.platform === "darwin";
const startStr: string = isMac ? " _" : "<";
const offsetStr: string = isMac ? " + " : "+";
const endOffsetStr: string = isMac ? " " : " <";
const dotStr: string = "…";
data += lines[0]; // signal type
const signalType: string = lines[0];
let crashCallStack: string = "";
for (let lineNum: number = 2; lineNum < lines.length - 3; ++lineNum) { // skip first/last lines
if (lineNum > 1) {
data += "\n";
addressData += "\n";
}
crashCallStack += "\n";
addressData += "\n";
const line: string = lines[lineNum];
const startPos: number = line.indexOf(startStr);
if (startPos === -1 || line[startPos + (isMac ? 1 : 4)] === "+") {
data += dotStr;
crashCallStack += dotStr;
const startAddressPos: number = line.indexOf("0x");
const endAddressPos: number = line.indexOf(endOffsetStr, startAddressPos + 2);
if (startAddressPos === -1 || endAddressPos === -1 || startAddressPos >= endAddressPos) {
@@ -1154,7 +1158,7 @@ async function handleCrashFileRead(crashDirectory: string, crashFile: string, er
}
const offsetPos: number = line.indexOf(offsetStr, startPos + startStr.length);
if (offsetPos === -1) {
data += "Missing offsetStr";
crashCallStack += "Missing offsetStr";
continue; // unexpected
}
const startPos2: number = startPos + 1;
@@ -1174,32 +1178,43 @@ async function handleCrashFileRead(crashDirectory: string, crashFile: string, er
funcStr = funcStr.replace(/, std::allocator<std::string>/g, "");
}
}
data += funcStr + offsetStr;
crashCallStack += funcStr + offsetStr;
const offsetPos2: number = offsetPos + offsetStr.length;
if (isMac) {
data += line.substring(offsetPos2);
crashCallStack += line.substring(offsetPos2);
const startAddressPos: number = line.indexOf("0x");
if (startAddressPos === -1 || startAddressPos >= startPos) {
// unexpected
data += "<Missing 0x>";
crashCallStack += "<Missing 0x>";
continue;
}
addressData += `${line.substring(startAddressPos, startPos)}`;
} else {
const endPos: number = line.indexOf(">", offsetPos2);
if (endPos === -1) {
data += "<Missing > >";
crashCallStack += "<Missing > >";
continue; // unexpected
}
data += line.substring(offsetPos2, endPos);
crashCallStack += line.substring(offsetPos2, endPos);
}
}

if (crashCallStack !== prevCppCrashCallStackData) {
prevCppCrashCallStackData = crashCallStack;

const settings: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("C_Cpp", null);
if (lines.length >= 6 && util.getNumericLoggingLevel(settings.get<string>("loggingLevel")) >= 1) {
const out: vscode.OutputChannel = getCrashCallStacksChannel();
out.appendLine(`\n${isCppToolsSrv ? "cpptools-srv" : "cpptools"}\n${crashDate.toLocaleString()}\n${signalType}${crashCallStack}`);
}
}

data = telemetryHeader + signalType + crashCallStack;

if (data.length > 8192) { // The API has an 8k limit.
data = data.substring(0, 8191) + "…";
}

console.log(`Crash call stack:\n${data}`);
logCppCrashTelemetry(data, addressData);

await util.deleteFile(path.resolve(crashDirectory, crashFile)).catch(logAndReturn.undefined);
11 changes: 11 additions & 0 deletions Extension/src/logger.ts
Original file line number Diff line number Diff line change
@@ -74,6 +74,7 @@ export class Logger {

export let outputChannel: vscode.OutputChannel | undefined;
export let diagnosticsChannel: vscode.OutputChannel | undefined;
export let crashCallStacksChannel: vscode.OutputChannel | undefined;
export let debugChannel: vscode.OutputChannel | undefined;
export let warningChannel: vscode.OutputChannel | undefined;
export let sshChannel: vscode.OutputChannel | undefined;
@@ -98,6 +99,16 @@ export function getDiagnosticsChannel(): vscode.OutputChannel {
return diagnosticsChannel;
}

export function getCrashCallStacksChannel(): vscode.OutputChannel {
if (!crashCallStacksChannel) {
crashCallStacksChannel = vscode.window.createOutputChannel(localize("c.cpp.crash.call.stacks.title", "C/C++ Crash Call Stacks"));
crashCallStacksChannel.appendLine(localize({ key: "c.cpp.crash.call.stacks.description", comment: ["{0} is a URL."] },
"A C/C++ extension process has crashed. The crashing process name, date/time, signal, and call stack are below -- it would be helpful to include that in a bug report at {0}.",
"https://github.com/Microsoft/vscode-cpptools/issues"));
}
return crashCallStacksChannel;
}

export function getSshChannel(): vscode.OutputChannel {
if (!sshChannel) {
sshChannel = vscode.window.createOutputChannel(localize("c.cpp.ssh.channel", "{0}: SSH", "Cpptools"));

0 comments on commit 0ef77b5

Please sign in to comment.