@@ -1033,27 +1033,19 @@ impl DebugSession {
10331033 if let Some ( child) = child {
10341034 let addr = child. load_address ( ) ;
10351035 if addr != lldb:: INVALID_ADDRESS {
1036- let size = child. byte_size ( ) ;
1037- if self . is_valid_watchpoint_size ( size) {
1038- let data_id = format ! ( "{}/{}" , addr, size) ;
1039- let desc = child. name ( ) . unwrap_or ( "" ) ;
1040- Ok ( DataBreakpointInfoResponseBody {
1041- data_id : Some ( data_id) ,
1042- access_types : Some ( vec ! [
1043- DataBreakpointAccessType :: Read ,
1044- DataBreakpointAccessType :: Write ,
1045- DataBreakpointAccessType :: ReadWrite ,
1046- ] ) ,
1047- description : format ! ( "{} bytes at {:X} ({})" , size, addr, desc) ,
1048- ..Default :: default ( )
1049- } )
1050- } else {
1051- Ok ( DataBreakpointInfoResponseBody {
1052- data_id : None ,
1053- description : "Invalid watchpoint size." . into ( ) ,
1054- ..Default :: default ( )
1055- } )
1056- }
1036+ let size = args. bytes . unwrap_or ( child. byte_size ( ) as i64 ) as usize ;
1037+ let data_id = format ! ( "{}/{}" , addr, size) ;
1038+ let desc = child. name ( ) . unwrap_or ( "" ) ;
1039+ Ok ( DataBreakpointInfoResponseBody {
1040+ data_id : Some ( data_id) ,
1041+ access_types : Some ( vec ! [
1042+ DataBreakpointAccessType :: Read ,
1043+ DataBreakpointAccessType :: Write ,
1044+ DataBreakpointAccessType :: ReadWrite ,
1045+ ] ) ,
1046+ description : format ! ( "{} bytes at {:X} ({})" , size, addr, desc) ,
1047+ ..Default :: default ( )
1048+ } )
10571049 } else {
10581050 Ok ( DataBreakpointInfoResponseBody {
10591051 data_id : None ,
@@ -1099,12 +1091,6 @@ impl DebugSession {
10991091 description : format ! ( "Invalid address {}" , addr) ,
11001092 ..Default :: default ( )
11011093 } )
1102- } else if self . is_valid_watchpoint_size ( size) {
1103- Ok ( DataBreakpointInfoResponseBody {
1104- data_id : None ,
1105- description : format ! ( "Invalid size {} for watchpoint" , size) ,
1106- ..Default :: default ( )
1107- } )
11081094 } else {
11091095 Ok ( DataBreakpointInfoResponseBody {
11101096 data_id : Some ( format ! ( "{}/{}" , addr, size) ) ,
@@ -1124,26 +1110,18 @@ impl DebugSession {
11241110 let addr = result. load_address ( ) ;
11251111 if addr != lldb:: INVALID_ADDRESS {
11261112 let size = args. bytes . unwrap_or ( result. byte_size ( ) as i64 ) as usize ;
1127- if self . is_valid_watchpoint_size ( size) {
1128- let data_id = format ! ( "{}/{}" , addr, size) ;
1129- let desc = result. name ( ) . unwrap_or ( expr) ;
1130- Ok ( DataBreakpointInfoResponseBody {
1131- data_id : Some ( data_id) ,
1132- access_types : Some ( vec ! [
1133- DataBreakpointAccessType :: Read ,
1134- DataBreakpointAccessType :: Write ,
1135- DataBreakpointAccessType :: ReadWrite ,
1136- ] ) ,
1137- description : format ! ( "{} bytes at {:X} ({})" , size, addr, desc) ,
1138- ..Default :: default ( )
1139- } )
1140- } else {
1141- Ok ( DataBreakpointInfoResponseBody {
1142- data_id : None ,
1143- description : format ! ( "Expression '{}' results in invalid watchpoint size: {}." , expr, size) ,
1144- ..Default :: default ( )
1145- } )
1146- }
1113+ let data_id = format ! ( "{}/{}" , addr, size) ;
1114+ let desc = result. name ( ) . unwrap_or ( expr) ;
1115+ Ok ( DataBreakpointInfoResponseBody {
1116+ data_id : Some ( data_id) ,
1117+ access_types : Some ( vec ! [
1118+ DataBreakpointAccessType :: Read ,
1119+ DataBreakpointAccessType :: Write ,
1120+ DataBreakpointAccessType :: ReadWrite ,
1121+ ] ) ,
1122+ description : format ! ( "{} bytes at {:X} ({})" , size, addr, desc) ,
1123+ ..Default :: default ( )
1124+ } )
11471125 } else {
11481126 Ok ( DataBreakpointInfoResponseBody {
11491127 data_id : None ,
@@ -1192,18 +1170,52 @@ impl DebugSession {
11921170 ( true , true ) => "read and write" ,
11931171 _ => unreachable ! ( ) ,
11941172 } ;
1195- let res = match self . target . watch_address ( addr, size, read, write) {
1196- Ok ( _wp) => Breakpoint {
1197- verified : true ,
1198- message : Some ( format ! ( "Break on {}" , when) ) ,
1199- ..Default :: default ( )
1200- } ,
1201- Err ( err) => Breakpoint {
1202- verified : false ,
1203- message : Some ( err. to_string ( ) ) ,
1204- ..Default :: default ( )
1205- } ,
1173+
1174+ // In LLDB, if you ask for a watchpoint on a variable (watch
1175+ // set variable foo), and foo's size > the hardware watchpoint size
1176+ // (e.g. 8 bytes), it actually creates N watchpoints, each of size 8
1177+ // bytes, to cover the entire size of 'foo'. We don't implement that
1178+ // here, rather requiring the user to manually add watchpoints to
1179+ // each word. So we do the same.
1180+ let ( required_watchpoints, wp_size) = if self . is_valid_watchpoint_size ( size) {
1181+ ( 1 , size)
1182+ } else {
1183+ ( ( size + self . target . address_byte_size ( ) - 1 ) / self . target . address_byte_size ( ) ,
1184+ self . target . address_byte_size ( ) )
1185+ } ;
1186+
1187+ let mut res = Breakpoint {
1188+ verified : true ,
1189+ message : Some ( format ! ( "{} watchpoints on {} to {} bytes at {}" , required_watchpoints, when, size, addr) ) ,
1190+ ..Default :: default ( )
12061191 } ;
1192+
1193+ let mut wps = vec ! [ ] ;
1194+ for i in 0 ..required_watchpoints {
1195+ let offset = ( self . target . address_byte_size ( ) * i as usize ) as u64 ;
1196+ match self . target . watch_address ( addr + offset, wp_size, read, write) {
1197+ Ok ( wp) => wps. push ( wp) ,
1198+ Err ( err) => {
1199+ res = Breakpoint {
1200+ verified : false ,
1201+ message : Some ( err. to_string ( ) ) ,
1202+ ..Default :: default ( )
1203+ } ;
1204+ break ;
1205+ }
1206+ } ;
1207+ }
1208+
1209+ // Undo on partial failure
1210+ // If we need to create N watchpoints, then we should do so
1211+ // atomically, i.e. if any of them fail, we should remove the ones
1212+ // that succeeded
1213+ if !res. verified {
1214+ for wp in wps {
1215+ self . target . delete_watchpoint ( wp. id ( ) ) ;
1216+ }
1217+ }
1218+
12071219 watchpoints. push ( res) ;
12081220 }
12091221 Ok ( SetDataBreakpointsResponseBody {
0 commit comments