Status FBIDBServiceHandler::dap()

in idb_companion/Server/FBIDBServiceHandler.mm [1554:1621]


Status FBIDBServiceHandler::dap(grpc::ServerContext *context, grpc::ServerReaderWriter<idb::DapResponse, idb::DapRequest> *stream)
{@autoreleasepool{
  idb::DapRequest initial_request;
  stream->Read(&initial_request);
  if (initial_request.control_case() != idb::DapRequest::ControlCase::kStart) {
    return Status(grpc::StatusCode::FAILED_PRECONDITION, "Dap command expected a Start messaged in the beginning of the Stream");
  }
  idb::DapRequest_Start start = initial_request.start();
  NSString *pkg_id = nsstring_from_c_string(start.debugger_pkg_id());
  NSString *lldb_vscode = [@"dap" stringByAppendingPathComponent:[pkg_id stringByAppendingPathComponent: @"usr/bin/lldb-vscode"]];

  id<FBDataConsumer> reader = [FBBlockDataConsumer synchronousDataConsumerWithBlock:^(NSData *data) {
    idb::DapResponse response;
    idb::DapResponse_Pipe *stdout = response.mutable_stdout();
    stdout->set_data(data.bytes, data.length);
    stream->Write(response);
    [_target.logger.debug logFormat:@"Dap server stdout consumer: sent %lu bytes.", data.length];
  }];


  [_target.logger.debug logFormat:@"Starting dap server with path %@", lldb_vscode];
  NSError *error = nil;
  FBProcessInput<id<FBDataConsumer>> *writer = [FBProcessInput inputFromConsumer];
  FBProcess *process = [[_commandExecutor dapServerWithPath:lldb_vscode stdIn:writer stdOut:reader] awaitWithTimeout:600 error:&error];
  if (error){
    NSString *errorMsg = [NSString stringWithFormat:@"Failed to spaw DAP server. Error: %@", error.localizedDescription];
    return Status(grpc::StatusCode::INTERNAL, errorMsg.UTF8String);
  }
  [_target.logger.debug logFormat:@"Dap server spawn with PID: %d", process.processIdentifier];
  idb::DapResponse response;
  response.mutable_started();
  stream->Write(response);

  dispatch_queue_t write_queue = dispatch_queue_create("com.facebook.idb.dap.write", DISPATCH_QUEUE_SERIAL);
  auto writeFuture = [FBFuture onQueue:write_queue resolveWhen:^BOOL {
    idb::DapRequest request;
    stream->Read(&request);
    if (request.control_case() == idb::DapRequest::ControlCase::kStop){
      [_target.logger.debug logFormat:@"Received stop from Dap Request"];
      [_target.logger.debug logFormat:@"Dap server with pid %d. Stderr: %@", process.processIdentifier, process.stdErr];
      return YES;
    }

    idb::DapRequest_Pipe pipe = request.pipe();
    auto raw_data = pipe.data();
    NSData *data = [NSData dataWithBytes:raw_data.c_str() length:raw_data.length()];
    if (data.length == 0) {
      [_target.logger.debug logFormat:@"Dap Request. Receiving empty messages. Transmission finished."];
      return YES;
    }
    [_target.logger.debug logFormat:@"Dap Request. Received %lu bytes from client", data.length];
    [writer.contents consumeData:data];
    return NO;
  }];

  //  Debug session shouln't be longer than 10hours
  [writeFuture awaitWithTimeout:36000 error:&error];
  if (error){
    NSString *errorMsg = [NSString stringWithFormat:@"Error in writting to dap server stdout: %@", error.localizedDescription];
    return Status(grpc::StatusCode::INTERNAL, errorMsg.UTF8String);
  }

  idb::DapResponse_Event *stopped = response.mutable_stopped();
  stopped->set_desc(@"Dap server stopped.".UTF8String);
  stream->Write(response);

  return Status::OK;
}}