1/** 2 * Copyright (c) 2021 Expo, Inc. 3 * Copyright (c) 2018 Drifty Co. 4 * 5 * This source code is licensed under the MIT license found in the 6 * LICENSE file in the root directory of this source tree. 7 */ 8import Debug from 'debug'; 9import { Socket } from 'net'; 10import * as path from 'path'; 11 12import { ServiceClient } from './ServiceClient'; 13import { GDBProtocolClient } from '../protocol/GDBProtocol'; 14 15const debug = Debug('expo:apple-device:client:debugserver'); 16 17export class DebugserverClient extends ServiceClient<GDBProtocolClient> { 18 constructor(public socket: Socket) { 19 super(socket, new GDBProtocolClient(socket)); 20 } 21 22 async setMaxPacketSize(size: number) { 23 return this.sendCommand('QSetMaxPacketSize:', [size.toString()]); 24 } 25 26 async setWorkingDir(workingDir: string) { 27 return this.sendCommand('QSetWorkingDir:', [workingDir]); 28 } 29 30 async checkLaunchSuccess() { 31 return this.sendCommand('qLaunchSuccess', []); 32 } 33 34 async attachByName(name: string) { 35 const hexName = Buffer.from(name).toString('hex'); 36 return this.sendCommand(`vAttachName;${hexName}`, []); 37 } 38 39 async continue() { 40 return this.sendCommand('c', []); 41 } 42 43 halt() { 44 // ^C 45 debug('Sending ^C to debugserver'); 46 return this.protocolClient.socket.write('\u0003'); 47 } 48 49 async kill() { 50 debug(`kill`); 51 const msg: any = { cmd: 'k', args: [] }; 52 return this.protocolClient.sendMessage(msg, (resp: string, resolve: any) => { 53 debug(`kill:response: ${resp}`); 54 this.protocolClient.socket.write('+'); 55 const parts = resp.split(';'); 56 for (const part of parts) { 57 if (part.includes('description')) { 58 // description:{hex encoded message like: "Terminated with signal 9"} 59 resolve(Buffer.from(part.split(':')[1], 'hex').toString('ascii')); 60 } 61 } 62 }); 63 } 64 65 // TODO support app args 66 // https://sourceware.org/gdb/onlinedocs/gdb/Packets.html#Packets 67 // A arglen,argnum,arg, 68 async launchApp(appPath: string, executableName: string) { 69 const fullPath = path.join(appPath, executableName); 70 const hexAppPath = Buffer.from(fullPath).toString('hex'); 71 const appCommand = `A${hexAppPath.length},0,${hexAppPath}`; 72 return this.sendCommand(appCommand, []); 73 } 74 75 async sendCommand(cmd: string, args: string[]) { 76 const msg = { cmd, args }; 77 debug(`Sending command: ${cmd}, args: ${args}`); 78 const resp = await this.protocolClient.sendMessage(msg); 79 // we need to ACK as well 80 this.protocolClient.socket.write('+'); 81 return resp; 82 } 83} 84