@@ -1085,11 +1085,15 @@ class GDBSignalWatcher extends stream.Writable {
1085
1085
}
1086
1086
1087
1087
export class GDBServer implements Mobile . IGDBServer {
1088
+ private okResponse = "$OK#" ;
1089
+ private isInitilized = false ;
1090
+
1088
1091
constructor ( private socket : any , // socket is fd on Windows and net.Socket on mac
1089
1092
private $injector : IInjector ,
1090
1093
private $hostInfo : IHostInfo ,
1091
1094
private $options : ICommonOptions ,
1092
- private $logger : ILogger ) {
1095
+ private $logger : ILogger ,
1096
+ private $errors : IErrors ) {
1093
1097
if ( this . $hostInfo . isWindows ) {
1094
1098
let winSocket = this . $injector . resolve ( WinSocket , { service : this . socket , format : 0 } ) ;
1095
1099
this . socket = {
@@ -1098,60 +1102,135 @@ export class GDBServer implements Mobile.IGDBServer {
1098
1102
}
1099
1103
} ;
1100
1104
}
1105
+
1106
+ this . socket . on ( "close" , ( hadError : boolean ) => this . $logger . trace ( "GDB socket get closed. HadError" , hadError . toString ( ) ) ) ;
1101
1107
}
1102
1108
1103
- public init ( ) : IFuture < void > {
1109
+ public init ( argv : string [ ] ) : IFuture < void > {
1104
1110
return ( ( ) => {
1105
- this . send ( "QStartNoAckMode" ) ;
1106
- this . socket . write ( "+" ) ;
1107
- this . send ( "QEnvironmentHexEncoded:" ) ;
1108
- this . send ( "QSetDisableASLR:1" ) ;
1111
+ if ( ! this . isInitilized ) {
1112
+ this . awaitResponse ( "QStartNoAckMode" , "+" ) . wait ( ) ;
1113
+ this . sendCore ( "+" ) ;
1114
+ this . awaitResponse ( "QEnvironmentHexEncoded:" ) . wait ( ) ;
1115
+ this . awaitResponse ( "QSetDisableASLR:1" ) . wait ( ) ;
1116
+ let encodedArguments = _ . map ( argv , ( arg , index ) => util . format ( "%d,%d,%s" , arg . length * 2 , index , this . toHex ( arg ) ) ) . join ( "," ) ;
1117
+ this . awaitResponse ( "A" + encodedArguments ) . wait ( ) ;
1118
+
1119
+ this . isInitilized = true ;
1120
+ }
1109
1121
} ) . future < void > ( ) ( ) ;
1110
1122
}
1111
1123
1112
1124
public run ( argv : string [ ] ) : IFuture < void > {
1113
1125
return ( ( ) => {
1114
- this . init ( ) . wait ( ) ;
1126
+ this . init ( argv ) . wait ( ) ;
1115
1127
1116
- let encodedArguments = _ . map ( argv , ( arg , index ) => util . format ( "%d,%d,%s" , arg . length * 2 , index , this . toHex ( arg ) ) ) . join ( "," ) ;
1117
- this . send ( "A" + encodedArguments ) ;
1118
-
1119
- this . send ( "qLaunchSuccess" ) ;
1128
+ this . awaitResponse ( "qLaunchSuccess" ) . wait ( ) ;
1120
1129
1121
1130
if ( this . $hostInfo . isWindows ) {
1122
1131
this . send ( "vCont;c" ) ;
1123
1132
} else {
1124
1133
if ( this . $options . justlaunch ) {
1125
1134
// Disconnecting the debugger closes the socket and allows the process to quit
1126
- this . send ( "D" ) ;
1135
+ this . sendCore ( this . encodeData ( "vCont;c" ) ) ;
1127
1136
} else {
1128
1137
this . socket . pipe ( new GDBStandardOutputAdapter ( ) ) . pipe ( process . stdout ) ;
1129
1138
this . socket . pipe ( new GDBSignalWatcher ( ) ) ;
1130
- this . send ( "vCont;c" ) ;
1139
+ this . sendCore ( this . encodeData ( "vCont;c" ) ) ;
1131
1140
}
1132
1141
}
1133
- this . socket . destroy ( ) ;
1134
1142
} ) . future < void > ( ) ( ) ;
1135
1143
}
1136
1144
1137
- public kill ( bundleExecutableName ? : string ) : IFuture < void > {
1145
+ public kill ( argv : string [ ] ) : IFuture < void > {
1138
1146
return ( ( ) => {
1139
- this . init ( ) . wait ( ) ;
1147
+ this . init ( argv ) . wait ( ) ;
1148
+
1149
+ this . awaitResponse ( "\x03" , "thread" , ( ) => this . sendx03Message ( ) ) . wait ( ) ;
1150
+ this . send ( "k" ) . wait ( ) ;
1151
+ } ) . future < void > ( ) ( ) ;
1152
+ }
1140
1153
1141
- let bundleExecutableNameHex = this . toHex ( bundleExecutableName ) ;
1142
- this . send ( `vAttachName;${ bundleExecutableNameHex } ` ) ;
1143
- this . send ( "k" ) ;
1144
- this . socket . destroy ( ) ;
1154
+ public destory ( ) : void {
1155
+ this . socket . destroy ( ) ;
1156
+ }
1157
+
1158
+ private awaitResponse ( packet : string , expectedResponse ?: string , getResponseAction ?: ( ) => IFuture < string > ) : IFuture < void > {
1159
+ return ( ( ) => {
1160
+ expectedResponse = expectedResponse || this . okResponse ;
1161
+ let actualResponse = getResponseAction ? getResponseAction . apply ( this , [ ] ) . wait ( ) : this . send ( packet ) . wait ( ) ;
1162
+ if ( actualResponse . indexOf ( expectedResponse ) === - 1 || _ . startsWith ( actualResponse , "$E" ) ) {
1163
+ this . $logger . trace ( `GDB: actual response: ${ actualResponse } , expected response: ${ expectedResponse } ` ) ;
1164
+ this . $errors . failWithoutHelp ( `Unable to send ${ packet } .` ) ;
1165
+ }
1145
1166
} ) . future < void > ( ) ( ) ;
1146
1167
}
1147
1168
1148
- private send ( packet : string ) : void {
1149
- let data = this . createData ( packet ) ;
1150
- this . $logger . trace ( `GDB: sending ${ data } ` ) ;
1169
+ private send ( packet : string ) : IFuture < string > {
1170
+ let future = new Future < string > ( ) ;
1171
+
1172
+ let dataCallback = ( data : any ) => {
1173
+ this . $logger . trace ( `GDB: read packet: ${ data } ` ) ;
1174
+ this . socket . removeListener ( "data" , dataCallback ) ;
1175
+ if ( ! future . isResolved ( ) ) {
1176
+ future . return ( data . toString ( ) ) ;
1177
+ }
1178
+ } ;
1179
+
1180
+ this . socket . on ( "data" , dataCallback ) ;
1181
+ this . socket . on ( "error" , ( error : string ) => {
1182
+ if ( ! future . isResolved ( ) ) {
1183
+ future . throw ( new Error ( error ) ) ;
1184
+ }
1185
+ } ) ;
1186
+
1187
+ this . sendCore ( this . encodeData ( packet ) ) ;
1188
+
1189
+ return future ;
1190
+ }
1191
+
1192
+ private sendCore ( data : string ) : void {
1193
+ this . $logger . trace ( `GDB: send packet ${ data } ` ) ;
1151
1194
this . socket . write ( data ) ;
1152
1195
}
1153
1196
1154
- private createData ( packet : string ) : string {
1197
+ private sendx03Message ( ) : IFuture < string > {
1198
+ let future = new Future < string > ( ) ;
1199
+ let retryCount = 3 ;
1200
+ let isDataReceived = false ;
1201
+
1202
+ let dataCallback = ( data : any ) => {
1203
+ let dataAsString = data . toString ( ) ;
1204
+ if ( dataAsString . indexOf ( "thread" ) > - 1 ) {
1205
+ isDataReceived = true ;
1206
+ this . socket . removeListener ( "data" , dataCallback ) ;
1207
+ future . return ( data . toString ( ) ) ;
1208
+ }
1209
+ } ;
1210
+
1211
+ this . socket . on ( "data" , dataCallback ) ;
1212
+ this . sendCore ( "\x03" ) ;
1213
+
1214
+ let timer = setInterval ( ( ) => {
1215
+ this . sendCore ( "\x03" ) ;
1216
+ retryCount -- ;
1217
+
1218
+ let secondTimer = setInterval ( ( ) => {
1219
+ if ( isDataReceived || ! retryCount ) {
1220
+ clearInterval ( secondTimer ) ;
1221
+ clearInterval ( timer ) ;
1222
+ }
1223
+
1224
+ if ( ! retryCount ) {
1225
+ future . throw ( new Error ( "Unable to kill the application." ) ) ;
1226
+ }
1227
+ } , 1000 ) ;
1228
+ } , 1000 ) ;
1229
+
1230
+ return future ;
1231
+ }
1232
+
1233
+ private encodeData ( packet : string ) : string {
1155
1234
let sum = 0 ;
1156
1235
for ( let i = 0 ; i < packet . length ; i ++ ) {
1157
1236
sum += getCharacterCodePoint ( packet [ i ] ) ;
0 commit comments