Skip to content
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

solve the problem of failed parsing of STL containers #433

Merged
merged 1 commit into from
Sep 19, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Versioning].
- New `frameFilters` option for GDB that allows using custom frame filters,
enabled by default ([@JacquesLucke])
- Suppress error for hover as the user may just play with the mouse ([@oltolm]).
- solve the problem of failed parsing of containers ([@henryriley0])

## [0.27.0] - 2024-02-07

Expand Down
27 changes: 21 additions & 6 deletions src/backend/gdb_expansion.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { VariableObject } from "./backend";
import { MINode } from "./mi_parse";

const resultRegex = /^([a-zA-Z_\-][a-zA-Z0-9_\-]*|\[\d+\])\s*=\s*/;
const variableRegex = /^[a-zA-Z_\-][a-zA-Z0-9_\-]*/;
const resultRegex = /^([a-zA-Z_\-][a-zA-Z0-9_\-<> :(),]*|\[\d+\])\s*=\s*/;
const variableRegex = /^[a-zA-Z_\-\'\(][a-zA-Z0-9_\-\|\>\ \\\'\)\:]*/;
const errorRegex = /^\<.+?\>/;
const referenceStringRegex = /^(0x[0-9a-fA-F]+\s*)"/;
const referenceRegex = /^0x[0-9a-fA-F]+/;
Expand Down Expand Up @@ -105,14 +105,18 @@ export function expandValue(variableCreate: (arg: VariableObject | string, optio
const eqPos = value.indexOf("=");
const newValPos1 = value.indexOf("{");
const newValPos2 = value.indexOf(",");
const newValPos3 = value.indexOf("}");
let newValPos = newValPos1;
if (newValPos2 != -1 && newValPos2 < newValPos1)
newValPos = newValPos2;
if (newValPos != -1 && eqPos > newValPos || eqPos == -1) { // is value list
if (newValPos != -1 && eqPos > newValPos || eqPos == -1 || eqPos > newValPos3 && newValPos2 != -1 || value.startsWith("std::")) { // is value list
const values = [];
stack.push("[0]");
let val = parseValue();
stack.pop();
if(typeof val == "string" && val.endsWith('>')){
val = val.substring(0, val.length - 2);
}
values.push(createValue("[0]", val));
const remaining = value;
let i = 0;
Expand Down Expand Up @@ -191,18 +195,26 @@ export function expandValue(variableCreate: (arg: VariableObject | string, optio
return parseCString();
else if (value[0] == '{')
return parseTupleOrList();
else if(value.startsWith("std::")){
const eqPos = value.indexOf("=");
value = value.substring(eqPos + 2);
return parseValue();
}
else
return parsePrimitive();
};

parseResult = (pushToStack: boolean = false) => {
value = value.trim();
value = value.replace(/^static /, "");
value = value.replace(/^</, "").trim().replace(/^static /, "");
const variableMatch = resultRegex.exec(value);
if (!variableMatch)
return undefined;
value = value.substring(variableMatch[0].length).trim();
const name = variable = variableMatch[1];
let name = variable = variableMatch[1].trim();
const tmpName = name.split(" ");
if(tmpName.length > 1 && !name.includes("anonymous union") && !name.includes(',')){
name = tmpName[tmpName.length - 1];
}
if (pushToStack)
stack.push(variable);
const val = parseValue();
Expand Down Expand Up @@ -231,6 +243,9 @@ export function expandValue(variableCreate: (arg: VariableObject | string, optio
ref = variableCreate(getNamespace(name));
val = "...";
}
value = value.trim();
value = value.replace(/^, <No data fields>/, "");

return {
name: name,
value: val,
Expand Down
9 changes: 8 additions & 1 deletion src/mibase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,14 @@ export class MI2DebugSession extends DebugSession {
// TODO: this evaluates on an (effectively) unknown thread for multithreaded programs.
variable = await this.miDebugger.evalExpression(JSON.stringify(id), 0, 0);
try {
let expanded = expandValue(createVariable, variable.result("value"), id, variable);
let variableValue = variable.result("value");
const pattern = /'([^']*)' <repeats (\d+) times>/g;
variableValue = variableValue.replace(pattern, (_: any, char: string, count: string) => {
const repeatCount = parseInt(count, 10) + 1;
const repeatedArray = Array(repeatCount).fill(char);
return `{${repeatedArray.map(item => `'${item}'`).join(', ')}}`;
});
let expanded = expandValue(createVariable, variableValue, id, variable);
if (!expanded) {
this.sendErrorResponse(response, 2, `Could not expand variable`);
} else {
Expand Down
88 changes: 88 additions & 0 deletions src/test/unit/gdb_expansion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,4 +304,92 @@ suite("GDB Value Expansion", () => {
{ name: "floatval2", value: "234.45", variablesReference: 0 }
]);
});
test("std container values", () => {
let node = `std::vector of length 4, capacity 6 = {1, 2, 3, 4}`;
let variables = expandValue(variableCreate, node);
assert.strictEqual(variables[3].value, `4`);
node = `std::deque with 7 elements = {0, 1, 2, 3, 4, 5, 6}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[6].value, `6`);
node = `std::__cxx11::list = {[0] = 6, [1] = 7, [2] = 8, [3] = 9, [4] = 10}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[4].value, `10`);
node = `std::vector of length 4, capacity 6 = {std::vector of length 3, capacity 3 = {1, 2, 3}, std::vector of length 3, capacity 3 = {4, 5, 6}, std::vector of length 3, capacity 3 = {7, 8, 9}, std::vector of length 4, capacity 4 = {1, 2, 3, 4}}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[3].variablesReference.expanded[3].value, `4`);
node = `std::deque with 3 elements = {std::deque with 2 elements = {10, 20}, std::deque with 2 elements = {30, 40}, std::deque with 7 elements = {0, 1, 2, 3, 4, 5, 6}}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[2].variablesReference.expanded[6].value, `6`);
node = `std::__cxx11::list = {[0] = std::__cxx11::list = {[0] = 11, [1] = 12}, [1] = std::__cxx11::list = {[0] = 13, [1] = 14}, [2] = std::__cxx11::list = {[0] = 6, [1] = 7, [2] = 8, [3] = 9, [4] = 10}}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[2].variablesReference.expanded[4].value, `10`);
node = `std::forward_list = {[0] = 0, [1] = 1, [2] = 2, [3] = 3}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[3].value, `3`);
node = `std::set with 5 elements = {[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[4].value, `5`);
node = `std::multiset with 6 elements = {[0] = 1, [1] = 2, [2] = 2, [3] = 2, [4] = 3, [5] = 4}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[5].value, `4`);
node = `std::map with 3 elements = {[1] = \"one\", [2] = \"two\", [3] = \"three\"}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[2].value, `"three"`);
node = `std::multimap with 3 elements = {[1] = \"one\", [2] = \"two\", [2] = \"another two\"}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[2].value, `"another two"`);
node = `std::unordered_set with 5 elements = {[0] = 5, [1] = 2, [2] = 3, [3] = 1, [4] = 4}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[4].value, `4`);
node = `std::unordered_multiset with 6 elements = {[0] = 1, [1] = 2, [2] = 2, [3] = 2, [4] = 3, [5] = 4}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[5].value, `4`);
node = `std::unordered_map with 3 elements = {[3] = \"three\", [1] = \"one\", [2] = \"two\"}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[2].value, `"two"`);
node = `std::unordered_multimap with 3 elements = {[2] = \"another two\", [2] = \"two\", [1] = \"one\"}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[2].value, `"one"`);
node = `std::stack wrapping: std::deque with 2 elements = {1, 2}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[1].value, `2`);
node = `std::queue wrapping: std::deque with 2 elements = {1, 2}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[1].value, `2`);
node = `std::priority_queue wrapping: std::vector of length 3, capacity 4 = {4, 1, 3}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[2].value, `3`);
node = `std::bitset = {[0] = 1, [2] = 1, [4] = 1, [6] = 1, [7] = 1}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[3].value, `1`);
node = `{_M_elems = {1, 2, 3}}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[0].variablesReference.expanded[2].value, `3`);
node = `std::unique_ptr<int> = {get() = 0x5555555d7d20}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[0].name, `get()`);
assert.strictEqual(variables[0].value, `Object@*0x5555555d7d20`);
node = `std::unique_ptr<int []> = {get() = 0x5555555d7d40}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[0].name, `get()`);
assert.strictEqual(variables[0].value, `Object@*0x5555555d7d40`);
node = `std::shared_ptr<int> (use count 1, weak count 1) = {get() = 0x5555555d7d70}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[0].name, `get()`);
assert.strictEqual(variables[0].value, `Object@*0x5555555d7d70`);
node = `{<std::__atomic_base<int>> = {static _S_alignment = 4, _M_i = 0}, <No data fields>}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[0].name, `std::__atomic_base<int>>`);
assert.strictEqual(variables[0].variablesReference.expanded[1].name, `_M_i`);
assert.strictEqual(variables[0].variablesReference.expanded[1].value, `0`);
node = `{<std::__mutex_base> = {_M_mutex = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 0, __spins = 0, __elision = 0, __list = {__prev = 0x0, __next = 0x0}}, __size = '\\000' <repeats 39 times>, __align = 0}}, <No data fields>}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[0].variablesReference.expanded[0].variablesReference.expanded[0].variablesReference.expanded[7].variablesReference.expanded[1].name, `__next`);
assert.strictEqual(variables[0].variablesReference.expanded[0].variablesReference.expanded[0].variablesReference.expanded[7].variablesReference.expanded[1].value, `<nullptr>`);
node = `{static icase = <optimized out>, static nosubs = <optimized out>, static optimize = <optimized out>, static collate = <optimized out>, static ECMAScript = (unknown: 16), static basic = <optimized out>, static extended = <optimized out>, static awk = <optimized out>, static grep = <optimized out>, static egrep = <optimized out>, _M_flags = (unknown: 16), _M_loc = {static none = 0, static ctype = 1, static numeric = 2, static collate = 4, static time = 8, static monetary = 16, static messages = 32, static all = 63, _M_impl = 0x7ffff7fa8ce0, static _S_classic = <optimized out>, static _S_global = <optimized out>, static _S_categories = <optimized out>, static _S_once = <optimized out>, static _S_twinned_facets = <optimized out>}, _M_automaton = std::shared_ptr<const std::__detail::_NFA<std::__cxx11::regex_traits<char> >> (use count 1, weak count 0) = {get() = 0x5555555d81b0}}`;
variables = expandValue(variableCreate, node);
assert.strictEqual(variables[12].name, `_M_automaton`);
assert.strictEqual(variables[12].variablesReference.expanded[0].value, `Object@*0x5555555d81b0`);

});
});
Loading