Skip to content

Commit 8e7535e

Browse files
committed
[PDB Import] Initial support for loading locals
1 parent 4e6453c commit 8e7535e

2 files changed

Lines changed: 42 additions & 42 deletions

File tree

plugins/pdb-ng/src/parser.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use binaryninja::types::{
3434
EnumerationBuilder, NamedTypeReference, NamedTypeReferenceClass, StructureBuilder,
3535
StructureType, Type, TypeClass,
3636
};
37-
use binaryninja::variable::NamedDataVariableWithType;
37+
use binaryninja::variable::{NamedDataVariableWithType, NamedVariableWithType};
3838

3939
/// Megastruct for all the parsing
4040
/// Certain fields are only used by specific files, as marked below.
@@ -252,7 +252,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
252252
address,
253253
name,
254254
type_,
255-
locals: _,
255+
locals,
256256
..
257257
}) => {
258258
self.log(|| {
@@ -276,7 +276,29 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
276276
Some(address),
277277
Some(self.platform.clone()),
278278
vec![], // TODO : Components
279-
vec![], //TODO: local variables
279+
locals
280+
.iter()
281+
.filter_map(|v| {
282+
let Some(var_type) = &v.type_ else {
283+
return None;
284+
};
285+
if v.storage.len() != 1 {
286+
// TODO: how should we handle variables with multiple storage locations?
287+
return None;
288+
}
289+
290+
let mut var_loc = v.storage[0].location;
291+
if v.storage[0].base_relative {
292+
var_loc.storage -= self.arch.address_size() as i64;
293+
}
294+
Some(NamedVariableWithType {
295+
variable: var_loc,
296+
ty: var_type.clone(),
297+
name: v.name.clone(),
298+
auto_defined: false,
299+
})
300+
})
301+
.collect::<Vec<_>>(),
280302
));
281303
}
282304
_ => {}

plugins/pdb-ng/src/symbol_parser.rs

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ pub struct ParsedVariable {
109109
pub struct ParsedLocation {
110110
/// Location information
111111
pub location: Variable,
112-
/// Is the storage location relative to the base pointer? See [ParsedProcedureInfo.frame_offset]
112+
/// Is the storage location relative to the base pointer?
113113
pub base_relative: bool,
114114
/// Is the storage location relative to the stack pointer?
115115
pub stack_relative: bool,
@@ -943,7 +943,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
943943
// We need both of these to exist (not sure why they wouldn't)
944944
let (raw_type, fancy_type) = match (raw_type, fancy_type) {
945945
(Some(raw), Some(fancy)) => (raw, fancy),
946-
_ => return Ok((fancier_type, vec![])),
946+
_ => return Ok((fancier_type, locals)),
947947
};
948948

949949
let raw_params = raw_type.contents.parameters().ok_or(anyhow!("no params"))?;
@@ -1004,7 +1004,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
10041004
// enough parameter variables declared as parameters, the remaining parameters are
10051005
// the first however many locals. If you don't have enough of those, idk??
10061006
if expected_param_count > (parsed_params.len() + parsed_locals.len()) {
1007-
return Ok((fancier_type, vec![]));
1007+
return Ok((fancier_type, locals));
10081008
}
10091009
parsed_params.extend(parsed_locals);
10101010
}
@@ -1082,7 +1082,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
10821082
self.log(|| format!("Fancy type: {:#x?}", fancy_type));
10831083
self.log(|| format!("Result type: {:#x?}", fancier_type));
10841084

1085-
Ok((Some(fancier_type), vec![]))
1085+
Ok((Some(fancier_type), locals))
10861086
}
10871087

10881088
fn handle_procedure_symbol(
@@ -1678,12 +1678,10 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
16781678
is_param,
16791679
..
16801680
})) => {
1681-
let new_storage = storage.iter().map(|&var| var.location).collect::<Vec<_>>();
1682-
16831681
// See if the parameter really is a parameter. Sometimes they don't say they are
16841682
let mut really_is_param = *is_param;
1685-
for loc in &new_storage {
1686-
match loc {
1683+
for loc in storage.iter() {
1684+
match loc.location {
16871685
Variable {
16881686
ty: VariableSourceType::RegisterVariableSourceType,
16891687
..
@@ -1693,9 +1691,9 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
16931691
}
16941692
Variable {
16951693
ty: VariableSourceType::StackVariableSourceType,
1696-
storage,
1694+
storage: offset,
16971695
..
1698-
} if *storage >= 0 => {
1696+
} if offset >= 0 => {
16991697
// Sometimes you can get two locals at the same offset, both rbp+(x > 0)
17001698
// I'm guessing from looking at dumps from dia2dump that only the first
17011699
// one is considered a parameter, although there are times that I see
@@ -1704,42 +1702,22 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
17041702
// and only one would be useful anyway.
17051703
// Regardless of the mess, Binja can only handle one parameter per slot
17061704
// so we're just going to use the first one.
1707-
really_is_param = seen_offsets.insert(*storage);
1705+
really_is_param = seen_offsets.insert(offset);
17081706
}
17091707
_ => {}
17101708
}
17111709
}
17121710

1711+
let var = ParsedVariable {
1712+
name: name.clone(),
1713+
type_: type_.clone(),
1714+
storage: storage.clone(),
1715+
is_param: really_is_param,
1716+
};
17131717
if really_is_param {
1714-
params.push(ParsedVariable {
1715-
name: name.clone(),
1716-
type_: type_.clone(),
1717-
storage: new_storage
1718-
.into_iter()
1719-
.map(|loc| ParsedLocation {
1720-
location: loc,
1721-
// This has been handled now
1722-
base_relative: false,
1723-
stack_relative: false,
1724-
})
1725-
.collect(),
1726-
is_param: really_is_param,
1727-
});
1718+
params.push(var);
17281719
} else {
1729-
locals.push(ParsedVariable {
1730-
name: name.clone(),
1731-
type_: type_.clone(),
1732-
storage: new_storage
1733-
.into_iter()
1734-
.map(|loc| ParsedLocation {
1735-
location: loc,
1736-
// This has been handled now
1737-
base_relative: false,
1738-
stack_relative: false,
1739-
})
1740-
.collect(),
1741-
is_param: really_is_param,
1742-
});
1720+
locals.push(var);
17431721
}
17441722
}
17451723
Some(ParsedSymbol::Data(_)) => {

0 commit comments

Comments
 (0)