@@ -20,15 +20,17 @@ use crate::PDBParserInstance;
2020use anyhow:: { anyhow, Result } ;
2121use binaryninja:: architecture:: Architecture ;
2222use binaryninja:: binary_view:: BinaryViewExt ;
23- use binaryninja:: calling_convention:: CoreCallingConvention ;
23+ use binaryninja:: calling_convention:: { CallingConvention , CoreCallingConvention } ;
2424use binaryninja:: confidence:: { Conf , MAX_CONFIDENCE } ;
2525use binaryninja:: platform:: Platform ;
2626use binaryninja:: rc:: Ref ;
2727use binaryninja:: types:: {
2828 BaseStructure , EnumerationBuilder , EnumerationMember , FunctionParameter , MemberAccess ,
29- MemberScope , NamedTypeReference , NamedTypeReferenceClass , StructureBuilder , StructureMember ,
30- StructureType , Type , TypeBuilder , TypeClass ,
29+ MemberScope , NamedTypeReference , NamedTypeReferenceClass , ReturnValue , StructureBuilder ,
30+ StructureMember , StructureType , Type , TypeBuilder , TypeClass , ValueLocation ,
31+ ValueLocationComponent ,
3132} ;
33+ use binaryninja:: variable:: { Variable , VariableSourceType } ;
3234use pdb:: Error :: UnimplementedTypeKind ;
3335use pdb:: {
3436 ArgumentList , ArrayType , BaseClassType , BitfieldType , ClassKind , ClassType , EnumerateType ,
@@ -1143,30 +1145,12 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
11431145 }
11441146 }
11451147
1146- let mut fancy_return_type = return_type. clone ( ) ;
1148+ let mut fancy_return_value = ReturnValue {
1149+ ty : Conf :: new ( return_type. clone ( ) , MAX_CONFIDENCE ) ,
1150+ location : None ,
1151+ } ;
11471152 let mut fancy_arguments = arguments. clone ( ) ;
11481153
1149- if data. attributes . cxx_return_udt ( )
1150- || !self . can_fit_in_register ( data. return_type , finder, true )
1151- {
1152- // Return UDT??
1153- // This probably means the return value got pushed to the stack
1154- fancy_return_type =
1155- Type :: pointer ( & self . arch , & Conf :: new ( return_type. clone ( ) , MAX_CONFIDENCE ) ) ;
1156- fancy_arguments. insert (
1157- 0 ,
1158- FunctionParameter :: new (
1159- Conf :: new ( fancy_return_type. clone ( ) , MAX_CONFIDENCE ) ,
1160- "__return" . to_string ( ) ,
1161- None ,
1162- ) ,
1163- ) ;
1164- }
1165-
1166- if let Some ( this_ptr) = & this_pointer_type {
1167- self . insert_this_pointer ( & mut fancy_arguments, this_ptr. clone ( ) ) ?;
1168- }
1169-
11701154 let convention = self
11711155 . cv_call_t_to_calling_convention ( data. attributes . calling_convention ( ) )
11721156 . map ( |cc| Conf :: new ( cc, MAX_CONFIDENCE ) )
@@ -1180,6 +1164,37 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
11801164 }
11811165 } ) ;
11821166
1167+ if data. attributes . cxx_return_udt ( )
1168+ || !self . can_fit_in_register ( data. return_type , finder, true )
1169+ {
1170+ // Return UDT??
1171+ // This probably means the return value got pushed to the stack
1172+ if self . settings . get_bool_with_opts (
1173+ "pdb.features.passStructuresByValue" ,
1174+ & mut self . settings_query_opts ,
1175+ ) {
1176+ fancy_return_value. location =
1177+ self . indirect_return_value_location ( & convention, & fancy_return_value) ;
1178+ } else {
1179+ fancy_return_value. ty = Conf :: new (
1180+ Type :: pointer ( & self . arch , & return_type. clone ( ) ) ,
1181+ MAX_CONFIDENCE ,
1182+ ) ;
1183+ fancy_arguments. insert (
1184+ 0 ,
1185+ FunctionParameter :: new (
1186+ fancy_return_value. ty . clone ( ) ,
1187+ "__return" . to_string ( ) ,
1188+ None ,
1189+ ) ,
1190+ ) ;
1191+ }
1192+ }
1193+
1194+ if let Some ( this_ptr) = & this_pointer_type {
1195+ self . insert_this_pointer ( & mut fancy_arguments, this_ptr. clone ( ) ) ?;
1196+ }
1197+
11831198 let func = Type :: function_with_opts (
11841199 & Conf :: new ( return_type, MAX_CONFIDENCE ) ,
11851200 arguments. as_slice ( ) ,
@@ -1189,7 +1204,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
11891204 ) ;
11901205
11911206 let fancy_func = Type :: function_with_opts (
1192- & Conf :: new ( fancy_return_type , MAX_CONFIDENCE ) ,
1207+ fancy_return_value ,
11931208 fancy_arguments. as_slice ( ) ,
11941209 is_varargs,
11951210 convention,
@@ -1423,31 +1438,46 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
14231438 }
14241439 }
14251440
1426- let mut fancy_return_type = return_type. clone ( ) ;
1441+ let mut fancy_return_value = ReturnValue {
1442+ ty : return_type. clone ( ) ,
1443+ location : None ,
1444+ } ;
14271445 let mut fancy_arguments = arguments. clone ( ) ;
14281446
1447+ let convention = self
1448+ . cv_call_t_to_calling_convention ( data. attributes . calling_convention ( ) )
1449+ . map ( |cc| Conf :: new ( cc, MAX_CONFIDENCE ) )
1450+ . unwrap_or ( Conf :: new ( self . default_cc . clone ( ) , 0 ) ) ;
1451+ self . log ( || format ! ( "Convention: {:?}" , convention) ) ;
1452+
14291453 let mut return_stacky = data. attributes . cxx_return_udt ( ) ;
14301454 if let Some ( return_type_index) = data. return_type {
14311455 return_stacky |= !self . can_fit_in_register ( return_type_index, finder, true ) ;
14321456 }
14331457 if return_stacky {
14341458 // Stack return via a pointer in the first parameter
1435- fancy_return_type = Conf :: new (
1436- Type :: pointer ( & self . arch , & return_type. clone ( ) ) ,
1437- MAX_CONFIDENCE ,
1438- ) ;
1439- fancy_arguments. insert (
1440- 0 ,
1441- FunctionParameter :: new ( fancy_return_type. clone ( ) , "__return" . to_string ( ) , None ) ,
1442- ) ;
1459+ if self . settings . get_bool_with_opts (
1460+ "pdb.features.passStructuresByValue" ,
1461+ & mut self . settings_query_opts ,
1462+ ) {
1463+ fancy_return_value. location =
1464+ self . indirect_return_value_location ( & convention, & fancy_return_value) ;
1465+ } else {
1466+ fancy_return_value. ty = Conf :: new (
1467+ Type :: pointer ( & self . arch , & return_type. clone ( ) ) ,
1468+ MAX_CONFIDENCE ,
1469+ ) ;
1470+ fancy_arguments. insert (
1471+ 0 ,
1472+ FunctionParameter :: new (
1473+ fancy_return_value. ty . clone ( ) ,
1474+ "__return" . to_string ( ) ,
1475+ None ,
1476+ ) ,
1477+ ) ;
1478+ }
14431479 }
14441480
1445- let convention = self
1446- . cv_call_t_to_calling_convention ( data. attributes . calling_convention ( ) )
1447- . map ( |cc| Conf :: new ( cc, MAX_CONFIDENCE ) )
1448- . unwrap_or ( Conf :: new ( self . default_cc . clone ( ) , 0 ) ) ;
1449- self . log ( || format ! ( "Convention: {:?}" , convention) ) ;
1450-
14511481 let func = Type :: function_with_opts (
14521482 & return_type,
14531483 arguments. as_slice ( ) ,
@@ -1457,7 +1487,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
14571487 ) ;
14581488
14591489 let fancy_func = Type :: function_with_opts (
1460- & fancy_return_type ,
1490+ fancy_return_value ,
14611491 fancy_arguments. as_slice ( ) ,
14621492 is_varargs,
14631493 convention,
@@ -1815,8 +1845,13 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
18151845 Some ( ty) => {
18161846 // On x86_32, structures are stored on the stack directly
18171847 // On x64, they are put into pointers if they are not a int size
1818- // TODO: Ugly hack
1819- if self . arch . address_size ( ) == 4 || Self :: size_can_fit_in_register ( ty. width ( ) ) {
1848+ if self . arch . address_size ( ) == 4
1849+ || Self :: size_can_fit_in_register ( ty. width ( ) )
1850+ || self . settings . get_bool_with_opts (
1851+ "pdb.features.passStructuresByValue" ,
1852+ & mut self . settings_query_opts ,
1853+ )
1854+ {
18201855 args. push ( FunctionParameter :: new (
18211856 Conf :: new ( ty. clone ( ) , MAX_CONFIDENCE ) ,
18221857 "" . to_string ( ) ,
@@ -2372,4 +2407,58 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
23722407 _ => false ,
23732408 }
23742409 }
2410+
2411+ /// Determines if there is a non-default location for an indirect return value and returns
2412+ /// the location if there is one.
2413+ fn indirect_return_value_location (
2414+ & self ,
2415+ convention : & Conf < Ref < CoreCallingConvention > > ,
2416+ return_value : & ReturnValue ,
2417+ ) -> Option < Conf < ValueLocation > > {
2418+ // Non-POD data types are always returned as indirect values. The calling convention
2419+ // may not know this and try to place them in registers, so check the calling convention
2420+ // to see if it wants to pass indirectly.
2421+ // TODO: The structures themselves should have some kind of non-POD attribute so
2422+ // that the calling convention can determine this by default
2423+ let default_return_location = convention
2424+ . contents
2425+ . return_value_location ( return_value. clone ( ) ) ;
2426+ let default_return_indrect = default_return_location
2427+ . components
2428+ . iter ( )
2429+ . any ( |c| c. indirect ) ;
2430+ if default_return_indrect {
2431+ None
2432+ } else {
2433+ let variable = if let Some ( reg) = convention. contents . int_arg_registers ( ) . get ( 0 ) {
2434+ Variable :: new (
2435+ VariableSourceType :: RegisterVariableSourceType ,
2436+ 0 ,
2437+ reg. 0 as i64 ,
2438+ )
2439+ } else {
2440+ Variable :: new (
2441+ VariableSourceType :: StackVariableSourceType ,
2442+ 0 ,
2443+ self . arch . address_size ( ) as i64 ,
2444+ )
2445+ } ;
2446+ Some ( Conf :: new (
2447+ ValueLocation {
2448+ components : vec ! [ ValueLocationComponent {
2449+ variable,
2450+ offset: 0 ,
2451+ size: Some ( return_value. ty. contents. width( ) ) ,
2452+ indirect: true ,
2453+ returned_pointer: convention. contents. return_int_reg( ) . map( |reg| Variable :: new(
2454+ VariableSourceType :: RegisterVariableSourceType ,
2455+ 0 ,
2456+ reg. 0 as i64 ,
2457+ ) ) ,
2458+ } ] ,
2459+ } ,
2460+ MAX_CONFIDENCE ,
2461+ ) )
2462+ }
2463+ }
23752464}
0 commit comments