xref: /freebsd/contrib/llvm-project/lldb/tools/lldb-rpc/lldb-rpc-gen/server/RPCServerSourceEmitter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- RPCServerSourceEmitter.cpp ----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "RPCServerSourceEmitter.h"
10 #include "RPCCommon.h"
11 
12 #include "clang/AST/AST.h"
13 #include "clang/Frontend/CompilerInstance.h"
14 
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/ToolOutputFile.h"
18 #include "llvm/Support/raw_ostream.h"
19 
20 #include <map>
21 
22 using namespace clang;
23 using namespace lldb_rpc_gen;
24 
25 // For methods with pointer return types, it's important that we know how big
26 // the type of the pointee is. We must correctly size a buffer (in the form of a
27 // Bytes object) before we can actually use it.
28 static const std::map<llvm::StringRef, size_t> MethodsWithPointerReturnTypes = {
29     {"_ZN4lldb12SBModuleSpec12GetUUIDBytesEv", 16}, // sizeof(uuid_t) -> 16
30     {"_ZNK4lldb8SBModule12GetUUIDBytesEv", 16},     // sizeof(uuid_t) -> 16
31 };
32 
EmitMethod(const Method & method)33 void RPCServerSourceEmitter::EmitMethod(const Method &method) {
34   if (method.ContainsFunctionPointerParameter)
35     EmitCallbackFunction(method);
36 
37   EmitCommentHeader(method);
38   EmitFunctionHeader(method);
39   EmitFunctionBody(method);
40   EmitFunctionFooter();
41 }
42 
EmitCommentHeader(const Method & method)43 void RPCServerSourceEmitter::EmitCommentHeader(const Method &method) {
44   std::string CommentLine;
45   llvm::raw_string_ostream CommentStream(CommentLine);
46 
47   CommentStream << "// " << method.QualifiedName << "("
48                 << method.CreateParamListAsString(eServer) << ")";
49   if (method.IsConst)
50     CommentStream << " const";
51 
52   EmitLine("//------------------------------------------------------------");
53   EmitLine(CommentLine);
54   EmitLine("//------------------------------------------------------------");
55 }
56 
EmitFunctionHeader(const Method & method)57 void RPCServerSourceEmitter::EmitFunctionHeader(const Method &method) {
58   std::string FunctionHeader;
59   llvm::raw_string_ostream FunctionHeaderStream(FunctionHeader);
60   FunctionHeaderStream
61       << "bool rpc_server::" << method.MangledName
62       << "::HandleRPCCall(rpc_common::Connection &connection, RPCStream "
63          "&send, RPCStream &response) {";
64   EmitLine(FunctionHeader);
65   IndentLevel++;
66 }
67 
EmitFunctionBody(const Method & method)68 void RPCServerSourceEmitter::EmitFunctionBody(const Method &method) {
69   EmitLine("// 1) Make local storage for incoming function arguments");
70   EmitStorageForParameters(method);
71   EmitLine("// 2) Decode all function arguments");
72   EmitDecodeForParameters(method);
73   EmitLine("// 3) Call the method and encode the return value");
74   EmitMethodCallAndEncode(method);
75 }
76 
EmitFunctionFooter()77 void RPCServerSourceEmitter::EmitFunctionFooter() {
78   EmitLine("return true;");
79   IndentLevel--;
80   EmitLine("}");
81 }
82 
EmitStorageForParameters(const Method & method)83 void RPCServerSourceEmitter::EmitStorageForParameters(const Method &method) {
84   // If we have an instance method and it isn't a constructor, we'll need to
85   // emit a "this" pointer.
86   if (method.IsInstance && !method.IsCtor)
87     EmitStorageForOneParameter(method.ThisType, "this_ptr", method.Policy,
88                                /* IsFollowedByLen = */ false);
89   for (auto Iter = method.Params.begin(); Iter != method.Params.end(); Iter++) {
90     EmitStorageForOneParameter(Iter->Type, Iter->Name, method.Policy,
91                                Iter->IsFollowedByLen);
92     // Skip over the length parameter, we don't emit it.
93     if (!lldb_rpc_gen::TypeIsConstCharPtrPtr(Iter->Type) &&
94         Iter->IsFollowedByLen)
95       Iter++;
96   }
97 }
98 
EmitStorageForOneParameter(QualType ParamType,const std::string & ParamName,const PrintingPolicy & Policy,bool IsFollowedByLen)99 void RPCServerSourceEmitter::EmitStorageForOneParameter(
100     QualType ParamType, const std::string &ParamName,
101     const PrintingPolicy &Policy, bool IsFollowedByLen) {
102   // First, we consider `const char *`, `const char **`. They have special
103   // server-side types.
104   if (TypeIsConstCharPtr(ParamType)) {
105     EmitLine("rpc_common::ConstCharPointer " + ParamName + ";");
106     return;
107   } else if (TypeIsConstCharPtrPtr(ParamType)) {
108     EmitLine("rpc_common::StringList " + ParamName + ";");
109     return;
110   }
111 
112   QualType UnderlyingType =
113       lldb_rpc_gen::GetUnqualifiedUnderlyingType(ParamType);
114   const bool IsSBClass = lldb_rpc_gen::TypeIsSBClass(UnderlyingType);
115 
116   if (ParamType->isPointerType() && !IsSBClass) {
117     // Void pointer with no length is usually a baton for a callback. We're
118     // going to hold onto the pointer value so we can send it back to the
119     // client-side when we implement callbacks.
120     if (ParamType->isVoidPointerType() && !IsFollowedByLen) {
121       EmitLine("void * " + ParamName + " = nullptr;");
122       return;
123     }
124 
125     if (!ParamType->isFunctionPointerType()) {
126       EmitLine("Bytes " + ParamName + ";");
127       return;
128     }
129 
130     assert(ParamType->isFunctionPointerType() && "Unhandled pointer type");
131     EmitLine("rpc_common::function_ptr_t " + ParamName + " = nullptr;");
132     return;
133   }
134 
135   std::string StorageDeclaration;
136   llvm::raw_string_ostream StorageDeclarationStream(StorageDeclaration);
137 
138   UnderlyingType.print(StorageDeclarationStream, Policy);
139   StorageDeclarationStream << " ";
140   if (IsSBClass)
141     StorageDeclarationStream << "*";
142   StorageDeclarationStream << ParamName;
143   if (IsSBClass)
144     StorageDeclarationStream << " = nullptr";
145   else
146     StorageDeclarationStream << " = {}";
147   StorageDeclarationStream << ";";
148   EmitLine(StorageDeclaration);
149 }
150 
EmitDecodeForParameters(const Method & method)151 void RPCServerSourceEmitter::EmitDecodeForParameters(const Method &method) {
152   if (method.IsInstance && !method.IsCtor)
153     EmitDecodeForOneParameter(method.ThisType, "this_ptr", method.Policy);
154   for (auto Iter = method.Params.begin(); Iter != method.Params.end(); Iter++) {
155     EmitDecodeForOneParameter(Iter->Type, Iter->Name, method.Policy);
156     if (!lldb_rpc_gen::TypeIsConstCharPtrPtr(Iter->Type) &&
157         Iter->IsFollowedByLen)
158       Iter++;
159   }
160 }
161 
EmitDecodeForOneParameter(QualType ParamType,const std::string & ParamName,const PrintingPolicy & Policy)162 void RPCServerSourceEmitter::EmitDecodeForOneParameter(
163     QualType ParamType, const std::string &ParamName,
164     const PrintingPolicy &Policy) {
165   QualType UnderlyingType =
166       lldb_rpc_gen::GetUnqualifiedUnderlyingType(ParamType);
167 
168   if (TypeIsSBClass(UnderlyingType)) {
169     std::string DecodeLine;
170     llvm::raw_string_ostream DecodeLineStream(DecodeLine);
171     DecodeLineStream << ParamName << " = "
172                      << "RPCServerObjectDecoder<";
173     UnderlyingType.print(DecodeLineStream, Policy);
174     DecodeLineStream << ">(send, rpc_common::RPCPacket::ValueType::Argument);";
175     EmitLine(DecodeLine);
176     EmitLine("if (!" + ParamName + ")");
177     IndentLevel++;
178     EmitLine("return false;");
179     IndentLevel--;
180   } else {
181     EmitLine("if (!RPCValueDecoder(send, "
182              "rpc_common::RPCPacket::ValueType::Argument, " +
183              ParamName + "))");
184     IndentLevel++;
185     EmitLine("return false;");
186     IndentLevel--;
187   }
188 }
189 
CreateMethodCall(const Method & method)190 std::string RPCServerSourceEmitter::CreateMethodCall(const Method &method) {
191   std::string MethodCall;
192   llvm::raw_string_ostream MethodCallStream(MethodCall);
193   if (method.IsInstance) {
194     if (!method.IsCtor)
195       MethodCallStream << "this_ptr->";
196     MethodCallStream << method.BaseName;
197   } else
198     MethodCallStream << method.QualifiedName;
199 
200   std::vector<std::string> Args;
201   std::string FunctionPointerName;
202   for (auto Iter = method.Params.begin(); Iter != method.Params.end(); Iter++) {
203     std::string Arg;
204     // We must check for `const char *` and `const char **` first.
205     if (TypeIsConstCharPtr(Iter->Type)) {
206       // `const char *` is stored server-side as rpc_common::ConstCharPointer
207       Arg = Iter->Name + ".c_str()";
208     } else if (TypeIsConstCharPtrPtr(Iter->Type)) {
209       // `const char **` is stored server-side as rpc_common::StringList
210       Arg = Iter->Name + ".argv()";
211     } else if (lldb_rpc_gen::TypeIsSBClass(Iter->Type)) {
212       Arg = Iter->Name;
213       if (!Iter->Type->isPointerType())
214         Arg = "*" + Iter->Name;
215     } else if (Iter->Type->isPointerType() &&
216                !Iter->Type->isFunctionPointerType() &&
217                (!Iter->Type->isVoidPointerType() || Iter->IsFollowedByLen)) {
218       // We move pointers between the server and client as 'Bytes' objects.
219       // Pointers with length arguments will have their length filled in below.
220       // Pointers with no length arguments are assumed to behave like an array
221       // with length of 1, except for void pointers which are handled
222       // differently.
223       Arg = "(" + Iter->Type.getAsString(method.Policy) + ")" + Iter->Name +
224             ".GetData()";
225     } else if (Iter->Type->isFunctionPointerType()) {
226       // If we have a function pointer, we only want to pass something along if
227       // we got a real pointer.
228       Arg = Iter->Name + " ? " + method.MangledName + "_callback : nullptr";
229       FunctionPointerName = Iter->Name;
230     } else if (Iter->Type->isVoidPointerType() && !Iter->IsFollowedByLen &&
231                method.ContainsFunctionPointerParameter) {
232       // Assumptions:
233       //  - This is assumed to be the baton for the function pointer.
234       //  - This is assumed to come after the function pointer parameter.
235       // We always produce this regardless of the value of the baton argument.
236       Arg = "new CallbackInfo(" + FunctionPointerName + ", " + Iter->Name +
237             ", connection.GetConnectionID())";
238     } else
239       Arg = Iter->Name;
240 
241     if (Iter->Type->isRValueReferenceType())
242       Arg = "std::move(" + Arg + ")";
243     Args.push_back(Arg);
244 
245     if (!lldb_rpc_gen::TypeIsConstCharPtrPtr(Iter->Type) &&
246         Iter->IsFollowedByLen) {
247       std::string LengthArg = Iter->Name + ".GetSize()";
248       if (!Iter->Type->isVoidPointerType()) {
249         QualType UUT = lldb_rpc_gen::GetUnqualifiedUnderlyingType(Iter->Type);
250         LengthArg += " / sizeof(" + UUT.getAsString(method.Policy) + ")";
251       }
252       Args.push_back(LengthArg);
253       Iter++;
254     }
255   }
256   MethodCallStream << "(" << llvm::join(Args, ", ") << ")";
257 
258   return MethodCall;
259 }
260 
CreateEncodeLine(const std::string & Value,bool IsEncodingSBClass)261 std::string RPCServerSourceEmitter::CreateEncodeLine(const std::string &Value,
262                                                      bool IsEncodingSBClass) {
263   std::string EncodeLine;
264   llvm::raw_string_ostream EncodeLineStream(EncodeLine);
265 
266   if (IsEncodingSBClass)
267     EncodeLineStream << "RPCServerObjectEncoder(";
268   else
269     EncodeLineStream << "RPCValueEncoder(";
270 
271   EncodeLineStream
272       << "response, rpc_common::RPCPacket::ValueType::ReturnValue, ";
273   EncodeLineStream << Value;
274   EncodeLineStream << ");";
275   return EncodeLine;
276 }
277 
278 // There are 4 cases to consider:
279 // - const SBClass &: No need to do anything.
280 // - const foo &: No need to do anything.
281 // - SBClass &: The server and the client hold on to IDs to refer to specific
282 //   instances, so there's no need to send any information back to the client.
283 // - foo &: The client is sending us a value over the wire, but because the type
284 //   is mutable, we must send the changed value back in case the method call
285 //   mutated it.
286 //
287 // Updating a mutable reference is done as a return value from the RPC
288 // perspective. These return values need to be emitted after the method's return
289 // value, and they are emitted in the order in which they occur in the
290 // declaration.
EmitEncodesForMutableParameters(const std::vector<Param> & Params)291 void RPCServerSourceEmitter::EmitEncodesForMutableParameters(
292     const std::vector<Param> &Params) {
293   for (auto Iter = Params.begin(); Iter != Params.end(); Iter++) {
294     // No need to manually update an SBClass
295     if (lldb_rpc_gen::TypeIsSBClass(Iter->Type))
296       continue;
297 
298     if (!Iter->Type->isReferenceType() && !Iter->Type->isPointerType())
299       continue;
300 
301     // If we have a void pointer with no length, there's nothing to update. This
302     // is likely a baton for a callback. The same goes for function pointers.
303     if (Iter->Type->isFunctionPointerType() ||
304         (Iter->Type->isVoidPointerType() && !Iter->IsFollowedByLen))
305       continue;
306 
307     // No need to update pointers and references to const-qualified data.
308     QualType UnderlyingType = lldb_rpc_gen::GetUnderlyingType(Iter->Type);
309     if (UnderlyingType.isConstQualified())
310       continue;
311 
312     const std::string EncodeLine =
313         CreateEncodeLine(Iter->Name, /* IsEncodingSBClass = */ false);
314     EmitLine(EncodeLine);
315   }
316 }
317 
318 // There are 3 possible scenarios that this method can encounter:
319 // 1. The method has no return value and is not a constructor.
320 //    Only the method call itself is emitted.
321 // 2. The method is a constructor.
322 //    The call to the constructor is emitted in the encode line.
323 // 3. The method has a return value.
324 //    The method call is emitted and the return value is captured in a variable.
325 //    After that, an encode call is emitted with the variable that captured the
326 //    return value.
EmitMethodCallAndEncode(const Method & method)327 void RPCServerSourceEmitter::EmitMethodCallAndEncode(const Method &method) {
328   const std::string MethodCall = CreateMethodCall(method);
329 
330   // If this function returns nothing, we just emit the call and update any
331   // mutable references. Note that constructors have return type `void` so we
332   // must explicitly check for that here.
333   if (!method.IsCtor && method.ReturnType->isVoidType()) {
334     EmitLine(MethodCall + ";");
335     EmitEncodesForMutableParameters(method.Params);
336     return;
337   }
338 
339   static constexpr llvm::StringLiteral ReturnVariableName("__result");
340 
341   // If this isn't a constructor, we'll need to store the result of the method
342   // call in a result variable.
343   if (!method.IsCtor) {
344     // We need to determine what the appropriate return type is. Here is the
345     // strategy:
346     // 1.) `SBFoo` -> `SBFoo &&`
347     // 2.) If the type is a pointer other than `const char *` or `const char **`
348     //     or `void *`, the return type will be `Bytes` (e.g. `const uint8_t *`
349     //     -> `Bytes`).
350     // 3.) Otherwise, emit the exact same return type.
351     std::string ReturnTypeName;
352     std::string AssignLine;
353     llvm::raw_string_ostream AssignLineStream(AssignLine);
354     if (method.ReturnType->isPointerType() &&
355         !lldb_rpc_gen::TypeIsConstCharPtr(method.ReturnType) &&
356         !lldb_rpc_gen::TypeIsConstCharPtrPtr(method.ReturnType) &&
357         !method.ReturnType->isVoidPointerType()) {
358       llvm::StringRef MangledNameRef(method.MangledName);
359       auto Pos = MethodsWithPointerReturnTypes.find(MangledNameRef);
360       assert(Pos != MethodsWithPointerReturnTypes.end() &&
361              "Unable to determine the size of the return buffer");
362       if (Pos == MethodsWithPointerReturnTypes.end()) {
363         EmitLine(
364             "// Intentionally inserting a compiler error. lldb-rpc-gen "
365             "was unable to determine how large the return buffer should be.");
366         EmitLine("#error: \"unable to determine size of return buffer\"");
367         return;
368       }
369       AssignLineStream << "Bytes " << ReturnVariableName << "(" << MethodCall
370                        << ", " << Pos->second << ");";
371     } else {
372       if (lldb_rpc_gen::TypeIsSBClass(method.ReturnType)) {
373         // We want to preserve constness, so we don't strip qualifications from
374         // the underlying type
375         QualType UnderlyingReturnType =
376             lldb_rpc_gen::GetUnderlyingType(method.ReturnType);
377         ReturnTypeName =
378             UnderlyingReturnType.getAsString(method.Policy) + " &&";
379       } else
380         ReturnTypeName = method.ReturnType.getAsString(method.Policy);
381 
382       AssignLineStream << ReturnTypeName << " " << ReturnVariableName << " = "
383                        << MethodCall << ";";
384     }
385     EmitLine(AssignLine);
386   }
387 
388   const bool IsEncodingSBClass =
389       lldb_rpc_gen::TypeIsSBClass(method.ReturnType) || method.IsCtor;
390 
391   std::string ValueToEncode;
392   if (IsEncodingSBClass) {
393     if (method.IsCtor)
394       ValueToEncode = MethodCall;
395     else
396       ValueToEncode = "std::move(" + ReturnVariableName.str() + ")";
397   } else
398     ValueToEncode = ReturnVariableName.str();
399 
400   const std::string ReturnValueEncodeLine =
401       CreateEncodeLine(ValueToEncode, IsEncodingSBClass);
402   EmitLine(ReturnValueEncodeLine);
403   EmitEncodesForMutableParameters(method.Params);
404 }
405 
406 // NOTE: This contains most of the same knowledge as RPCLibrarySourceEmitter. I
407 // have chosen not to re-use code here because the needs are different enough
408 // that it would be more work to re-use than just reimplement portions of it.
409 // Specifically:
410 //  - Callbacks do not neatly fit into a `Method` object, which currently
411 //    assumes that you have a CXXMethodDecl (We have a FunctionDecl at most).
412 //  - We only generate callbacks that have a `void *` baton parameter. We hijack
413 //    those baton parameters and treat them differently.
414 //  - Callbacks need to do something special for moving SB class references back
415 //    to the client-side.
EmitCallbackFunction(const Method & method)416 void RPCServerSourceEmitter::EmitCallbackFunction(const Method &method) {
417   // Check invariants and locate necessary resources
418   Param FuncPointerParam;
419   Param BatonParam;
420   for (const auto &Param : method.Params)
421     if (Param.Type->isFunctionPointerType())
422       FuncPointerParam = Param;
423     else if (Param.Type->isVoidPointerType())
424       BatonParam = Param;
425 
426   assert(FuncPointerParam.Type->isFunctionPointerType() &&
427          "Emitting callback function with no function pointer");
428   assert(BatonParam.Type->isVoidPointerType() &&
429          "Emitting callback function with no baton");
430 
431   QualType FuncType = FuncPointerParam.Type->getPointeeType();
432   const auto *FuncProtoType = FuncType->getAs<FunctionProtoType>();
433   assert(FuncProtoType && "Emitting callback with no parameter information");
434   if (!FuncProtoType)
435     return; // If asserts are off, we'll just fail to compile.
436 
437   std::vector<Param> CallbackParams;
438   std::vector<std::string> CallbackParamsAsStrings;
439   uint8_t ArgIdx = 0;
440   for (QualType ParamType : FuncProtoType->param_types()) {
441     Param CallbackParam;
442     CallbackParam.IsFollowedByLen = false;
443     CallbackParam.Type = ParamType;
444     if (ParamType->isVoidPointerType())
445       CallbackParam.Name = "baton";
446     else
447       CallbackParam.Name = "arg" + std::to_string(ArgIdx++);
448 
449     CallbackParams.push_back(CallbackParam);
450     CallbackParamsAsStrings.push_back(ParamType.getAsString(method.Policy) +
451                                       " " + CallbackParam.Name);
452   }
453   const std::string CallbackReturnTypeName =
454       FuncProtoType->getReturnType().getAsString(method.Policy);
455   const std::string CallbackName = method.MangledName + "_callback";
456 
457   // Emit Function Header
458   std::string Header;
459   llvm::raw_string_ostream HeaderStream(Header);
460   HeaderStream << "static " << CallbackReturnTypeName << " " << CallbackName
461                << "(" << llvm::join(CallbackParamsAsStrings, ", ") << ") {";
462   EmitLine(Header);
463   IndentLevel++;
464 
465   // Emit Function Body
466   EmitLine("// RPC connection setup and sanity checking");
467   EmitLine("CallbackInfo *callback_info = (CallbackInfo *)baton;");
468   EmitLine("rpc_common::ConnectionSP connection_sp = "
469            "rpc_common::Connection::GetConnectionFromID(callback_info->"
470            "connection_id);");
471   EmitLine("if (!connection_sp)");
472   IndentLevel++;
473   if (FuncProtoType->getReturnType()->isVoidType())
474     EmitLine("return;");
475   else
476     EmitLine("return {};");
477   IndentLevel--;
478 
479   EmitLine("// Preparing to make the call");
480   EmitLine("static RPCFunctionInfo g_func(\"" + CallbackName + "\");");
481   EmitLine("RPCStream send;");
482   EmitLine("RPCStream response;");
483   EmitLine("g_func.Encode(send);");
484 
485   EmitLine("// The first thing we encode is the callback address so that the "
486            "client-side can know where the callback is");
487   EmitLine("RPCValueEncoder(send, rpc_common::RPCPacket::ValueType::Argument, "
488            "callback_info->callback);");
489   EmitLine("// Encode all the arguments");
490   for (const Param &CallbackParam : CallbackParams) {
491     if (lldb_rpc_gen::TypeIsSBClass(CallbackParam.Type)) {
492 
493       // FIXME: SB class server references are stored as non-const references so
494       // that we can actually change them as needed. If a parameter is marked
495       // const, we will fail to compile because we cannot make an
496       // SBFooServerReference from a `const SBFoo &`.
497       // To work around this issue, we'll apply a `const_cast` if needed so we
498       // can continue to generate callbacks for now, but we really should
499       // rethink the way we store object IDs server-side to support
500       // const-qualified parameters.
501       QualType UnderlyingSBClass =
502           lldb_rpc_gen::GetUnderlyingType(CallbackParam.Type);
503       QualType UnqualifiedUnderlyingSBClass =
504           UnderlyingSBClass.getUnqualifiedType();
505 
506       std::string SBClassName = GetSBClassNameFromType(UnderlyingSBClass);
507       llvm::StringRef SBClassNameRef(SBClassName);
508       SBClassNameRef.consume_front("lldb::");
509 
510       std::string ServerReferenceLine;
511       llvm::raw_string_ostream ServerReferenceLineStream(ServerReferenceLine);
512       ServerReferenceLineStream << "rpc_server::" << SBClassNameRef
513                                 << "ServerReference " << CallbackParam.Name
514                                 << "_ref(";
515 
516       if (UnderlyingSBClass.isConstQualified()) {
517         QualType NonConstSBType =
518             method.Context.getLValueReferenceType(UnqualifiedUnderlyingSBClass);
519         ServerReferenceLineStream << "const_cast<" << NonConstSBType << ">(";
520       }
521       ServerReferenceLineStream << CallbackParam.Name;
522       if (UnderlyingSBClass.isConstQualified())
523         ServerReferenceLineStream << ")";
524 
525       ServerReferenceLineStream << ");";
526       EmitLine(ServerReferenceLine);
527       EmitLine(
528           CallbackParam.Name +
529           "_ref.Encode(send, rpc_common::RPCPacket::ValueType::Argument);");
530     } else {
531       std::string ParamName;
532       if (CallbackParam.Type->isVoidPointerType())
533         ParamName = "callback_info->baton";
534       else
535         ParamName = CallbackParam.Name;
536       EmitLine(
537           "RPCValueEncoder(send, rpc_common::RPCPacket::ValueType::Argument, " +
538           ParamName + ");");
539     }
540   }
541 
542   if (!FuncProtoType->getReturnType()->isVoidType()) {
543     EmitLine("// Storage for return value");
544     const bool ReturnsSBClass =
545         lldb_rpc_gen::TypeIsSBClass(FuncProtoType->getReturnType());
546     std::string ReturnValueLine = CallbackReturnTypeName;
547     llvm::raw_string_ostream ReturnValueLineStream(ReturnValueLine);
548 
549     if (ReturnsSBClass)
550       ReturnValueLineStream << " *";
551     ReturnValueLineStream << " __result = ";
552     if (ReturnsSBClass)
553       ReturnValueLineStream << "nullptr";
554     else
555       ReturnValueLineStream << "{}";
556     ReturnValueLineStream << ";";
557     EmitLine(ReturnValueLine);
558   }
559 
560   EmitLine(
561       "if (connection_sp->SendRPCCallAndWaitForResponse(send, response)) {");
562   IndentLevel++;
563   if (!FuncProtoType->getReturnType()->isVoidType()) {
564     if (lldb_rpc_gen::TypeIsSBClass(FuncProtoType->getReturnType())) {
565       EmitLine("__result = rpc_server::RPCServerObjectDecoder<" +
566                CallbackReturnTypeName +
567                ">(response, rpc_common::RPCPacket::ValueType::ReturnValue);");
568     } else
569       EmitLine("RPCValueDecoder(response, "
570                "rpc_common::RPCPacket::ValueType::ReturnValue, __result);");
571   }
572   IndentLevel--;
573   EmitLine("}");
574   if (!FuncProtoType->getReturnType()->isVoidType()) {
575     if (lldb_rpc_gen::TypeIsSBClass(FuncProtoType->getReturnType()))
576       EmitLine("return *__result;");
577     else
578       EmitLine("return __result;");
579   }
580 
581   // Emit Function Footer;
582   IndentLevel--;
583   EmitLine("};");
584 }
585