xref: /reactos/dll/win32/rpcrt4/ndr_stubless.c (revision 5bfe6a53)
1 /*
2  * NDR -Oi,-Oif,-Oicf Interpreter
3  *
4  * Copyright 2001 Ove Kåven, TransGaming Technologies
5  * Copyright 2003-5 Robert Shearman (for CodeWeavers)
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * TODO:
22  *  - Pipes
23  *  - Some types of binding handles
24  */
25 
26 #include "config.h"
27 #include "wine/port.h"
28 
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 
37 #include "objbase.h"
38 #include "rpc.h"
39 #include "rpcproxy.h"
40 
41 #include "wine/exception.h"
42 #include "wine/debug.h"
43 
44 #include "cpsf.h"
45 #include "ndr_misc.h"
46 #include "ndr_stubless.h"
47 
48 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
49 
50 #define NDR_TABLE_MASK 127
51 
52 static inline BOOL is_oicf_stubdesc(const PMIDL_STUB_DESC pStubDesc)
53 {
54     return pStubDesc->Version >= 0x20000;
55 }
56 
57 static inline void call_buffer_sizer(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory,
58                                      const NDR_PARAM_OIF *param)
59 {
60     PFORMAT_STRING pFormat;
61     NDR_BUFFERSIZE m;
62 
63     if (param->attr.IsBasetype)
64     {
65         pFormat = &param->u.type_format_char;
66         if (param->attr.IsSimpleRef) pMemory = *(unsigned char **)pMemory;
67     }
68     else
69     {
70         pFormat = &pStubMsg->StubDesc->pFormatTypes[param->u.type_offset];
71         if (!param->attr.IsByValue) pMemory = *(unsigned char **)pMemory;
72     }
73 
74     m = NdrBufferSizer[pFormat[0] & NDR_TABLE_MASK];
75     if (m) m(pStubMsg, pMemory, pFormat);
76     else
77     {
78         FIXME("format type 0x%x not implemented\n", pFormat[0]);
79         RpcRaiseException(RPC_X_BAD_STUB_DATA);
80     }
81 }
82 
83 static inline unsigned char *call_marshaller(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory,
84                                              const NDR_PARAM_OIF *param)
85 {
86     PFORMAT_STRING pFormat;
87     NDR_MARSHALL m;
88 
89     if (param->attr.IsBasetype)
90     {
91         pFormat = &param->u.type_format_char;
92         if (param->attr.IsSimpleRef) pMemory = *(unsigned char **)pMemory;
93     }
94     else
95     {
96         pFormat = &pStubMsg->StubDesc->pFormatTypes[param->u.type_offset];
97         if (!param->attr.IsByValue) pMemory = *(unsigned char **)pMemory;
98     }
99 
100     m = NdrMarshaller[pFormat[0] & NDR_TABLE_MASK];
101     if (m) return m(pStubMsg, pMemory, pFormat);
102     else
103     {
104         FIXME("format type 0x%x not implemented\n", pFormat[0]);
105         RpcRaiseException(RPC_X_BAD_STUB_DATA);
106         return NULL;
107     }
108 }
109 
110 static inline unsigned char *call_unmarshaller(PMIDL_STUB_MESSAGE pStubMsg, unsigned char **ppMemory,
111                                                const NDR_PARAM_OIF *param, unsigned char fMustAlloc)
112 {
113     PFORMAT_STRING pFormat;
114     NDR_UNMARSHALL m;
115 
116     if (param->attr.IsBasetype)
117     {
118         pFormat = &param->u.type_format_char;
119         if (param->attr.IsSimpleRef) ppMemory = (unsigned char **)*ppMemory;
120     }
121     else
122     {
123         pFormat = &pStubMsg->StubDesc->pFormatTypes[param->u.type_offset];
124         if (!param->attr.IsByValue) ppMemory = (unsigned char **)*ppMemory;
125     }
126 
127     m = NdrUnmarshaller[pFormat[0] & NDR_TABLE_MASK];
128     if (m) return m(pStubMsg, ppMemory, pFormat, fMustAlloc);
129     else
130     {
131         FIXME("format type 0x%x not implemented\n", pFormat[0]);
132         RpcRaiseException(RPC_X_BAD_STUB_DATA);
133         return NULL;
134     }
135 }
136 
137 static inline void call_freer(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory,
138                               const NDR_PARAM_OIF *param)
139 {
140     PFORMAT_STRING pFormat;
141     NDR_FREE m;
142 
143     if (param->attr.IsBasetype) return;  /* nothing to do */
144     pFormat = &pStubMsg->StubDesc->pFormatTypes[param->u.type_offset];
145     if (!param->attr.IsByValue) pMemory = *(unsigned char **)pMemory;
146 
147     m = NdrFreer[pFormat[0] & NDR_TABLE_MASK];
148     if (m) m(pStubMsg, pMemory, pFormat);
149 }
150 
151 static DWORD calc_arg_size(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat)
152 {
153     DWORD size;
154     switch(*pFormat)
155     {
156     case FC_RP:
157         if (pFormat[1] & FC_SIMPLE_POINTER)
158         {
159             size = 0;
160             break;
161         }
162         size = calc_arg_size(pStubMsg, &pFormat[2] + *(const SHORT*)&pFormat[2]);
163         break;
164     case FC_STRUCT:
165     case FC_PSTRUCT:
166         size = *(const WORD*)(pFormat + 2);
167         break;
168     case FC_BOGUS_STRUCT:
169         size = *(const WORD*)(pFormat + 2);
170         if(*(const WORD*)(pFormat + 4))
171             FIXME("Unhandled conformant description\n");
172         break;
173     case FC_CARRAY:
174     case FC_CVARRAY:
175         size = *(const WORD*)(pFormat + 2);
176         ComputeConformance(pStubMsg, NULL, pFormat + 4, 0);
177         size *= pStubMsg->MaxCount;
178         break;
179     case FC_SMFARRAY:
180     case FC_SMVARRAY:
181         size = *(const WORD*)(pFormat + 2);
182         break;
183     case FC_LGFARRAY:
184     case FC_LGVARRAY:
185         size = *(const DWORD*)(pFormat + 2);
186         break;
187     case FC_BOGUS_ARRAY:
188         pFormat = ComputeConformance(pStubMsg, NULL, pFormat + 4, *(const WORD*)&pFormat[2]);
189         TRACE("conformance = %ld\n", pStubMsg->MaxCount);
190         pFormat = ComputeVariance(pStubMsg, NULL, pFormat, pStubMsg->MaxCount);
191         size = ComplexStructSize(pStubMsg, pFormat);
192         size *= pStubMsg->MaxCount;
193         break;
194     case FC_USER_MARSHAL:
195         size = *(const WORD*)(pFormat + 4);
196         break;
197     case FC_CSTRING:
198         size = *(const WORD*)(pFormat + 2);
199         break;
200     case FC_WSTRING:
201         size = *(const WORD*)(pFormat + 2) * sizeof(WCHAR);
202         break;
203     case FC_C_CSTRING:
204     case FC_C_WSTRING:
205         if (*pFormat == FC_C_CSTRING)
206             size = sizeof(CHAR);
207         else
208             size = sizeof(WCHAR);
209         if (pFormat[1] == FC_STRING_SIZED)
210             ComputeConformance(pStubMsg, NULL, pFormat + 2, 0);
211         else
212             pStubMsg->MaxCount = 0;
213         size *= pStubMsg->MaxCount;
214         break;
215     default:
216         FIXME("Unhandled type %02x\n", *pFormat);
217         /* fallthrough */
218     case FC_UP:
219     case FC_OP:
220     case FC_FP:
221     case FC_IP:
222         size = sizeof(void *);
223         break;
224     }
225     return size;
226 }
227 
228 void WINAPI NdrRpcSmSetClientToOsf(PMIDL_STUB_MESSAGE pMessage)
229 {
230 #if 0 /* these functions are not defined yet */
231     pMessage->pfnAllocate = NdrRpcSmClientAllocate;
232     pMessage->pfnFree = NdrRpcSmClientFree;
233 #endif
234 }
235 
236 static const char *debugstr_PROC_PF(PARAM_ATTRIBUTES param_attributes)
237 {
238     char buffer[160];
239 
240     buffer[0] = 0;
241     if (param_attributes.MustSize) strcat(buffer, " MustSize");
242     if (param_attributes.MustFree) strcat(buffer, " MustFree");
243     if (param_attributes.IsPipe) strcat(buffer, " IsPipe");
244     if (param_attributes.IsIn) strcat(buffer, " IsIn");
245     if (param_attributes.IsOut) strcat(buffer, " IsOut");
246     if (param_attributes.IsReturn) strcat(buffer, " IsReturn");
247     if (param_attributes.IsBasetype) strcat(buffer, " IsBasetype");
248     if (param_attributes.IsByValue) strcat(buffer, " IsByValue");
249     if (param_attributes.IsSimpleRef) strcat(buffer, " IsSimpleRef");
250     if (param_attributes.IsDontCallFreeInst) strcat(buffer, " IsDontCallFreeInst");
251     if (param_attributes.SaveForAsyncFinish) strcat(buffer, " SaveForAsyncFinish");
252     if (param_attributes.ServerAllocSize)
253         sprintf( buffer + strlen(buffer), " ServerAllocSize = %d", param_attributes.ServerAllocSize * 8);
254     return buffer[0] ? wine_dbg_sprintf( "%s", buffer + 1 ) : "";
255 }
256 
257 static const char *debugstr_INTERPRETER_OPT_FLAGS(INTERPRETER_OPT_FLAGS Oi2Flags)
258 {
259     char buffer[160];
260 
261     buffer[0] = 0;
262     if (Oi2Flags.ServerMustSize) strcat(buffer, " ServerMustSize");
263     if (Oi2Flags.ClientMustSize) strcat(buffer, " ClientMustSize");
264     if (Oi2Flags.HasReturn) strcat(buffer, " HasReturn");
265     if (Oi2Flags.HasPipes) strcat(buffer, " HasPipes");
266     if (Oi2Flags.Unused) strcat(buffer, " Unused");
267     if (Oi2Flags.HasAsyncUuid) strcat(buffer, " HasAsyncUuid");
268     if (Oi2Flags.HasExtensions) strcat(buffer, " HasExtensions");
269     if (Oi2Flags.HasAsyncHandle) strcat(buffer, " HasAsyncHandle");
270     return buffer[0] ? wine_dbg_sprintf( "%s", buffer + 1 ) : "";
271 }
272 
273 #define ARG_FROM_OFFSET(args, offset) ((args) + (offset))
274 
275 static PFORMAT_STRING client_get_handle(
276     PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader,
277     PFORMAT_STRING pFormat, handle_t *phBinding)
278 {
279     /* binding */
280     switch (pProcHeader->handle_type)
281     {
282     /* explicit binding: parse additional section */
283     case 0:
284         switch (*pFormat) /* handle_type */
285         {
286         case FC_BIND_PRIMITIVE: /* explicit primitive */
287             {
288                 const NDR_EHD_PRIMITIVE *pDesc = (const NDR_EHD_PRIMITIVE *)pFormat;
289 
290                 TRACE("Explicit primitive handle @ %d\n", pDesc->offset);
291 
292                 if (pDesc->flag) /* pointer to binding */
293                     *phBinding = **(handle_t **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
294                 else
295                     *phBinding = *(handle_t *)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
296                 return pFormat + sizeof(NDR_EHD_PRIMITIVE);
297             }
298         case FC_BIND_GENERIC: /* explicit generic */
299             {
300                 const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat;
301                 void *pObject = NULL;
302                 void *pArg;
303                 const GENERIC_BINDING_ROUTINE_PAIR *pGenPair;
304 
305                 TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index);
306 
307                 if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR)
308                     pArg = *(void **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
309                 else
310                     pArg = ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
311                 memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf);
312                 pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index];
313                 *phBinding = pGenPair->pfnBind(pObject);
314                 return pFormat + sizeof(NDR_EHD_GENERIC);
315             }
316         case FC_BIND_CONTEXT: /* explicit context */
317             {
318                 const NDR_EHD_CONTEXT *pDesc = (const NDR_EHD_CONTEXT *)pFormat;
319                 NDR_CCONTEXT context_handle;
320                 TRACE("Explicit bind context\n");
321                 if (pDesc->flags & HANDLE_PARAM_IS_VIA_PTR)
322                 {
323                     TRACE("\tHANDLE_PARAM_IS_VIA_PTR\n");
324                     context_handle = **(NDR_CCONTEXT **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
325                 }
326                 else
327                     context_handle = *(NDR_CCONTEXT *)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
328 
329                 if (context_handle) *phBinding = NDRCContextBinding(context_handle);
330                 else if (pDesc->flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL)
331                 {
332                     ERR("null context handle isn't allowed\n");
333                     RpcRaiseException(RPC_X_SS_IN_NULL_CONTEXT);
334                     return NULL;
335                 }
336                 /* FIXME: should we store this structure in stubMsg.pContext? */
337                 return pFormat + sizeof(NDR_EHD_CONTEXT);
338             }
339         default:
340             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
341             RpcRaiseException(RPC_X_BAD_STUB_DATA);
342         }
343         break;
344     case FC_BIND_GENERIC: /* implicit generic */
345         FIXME("FC_BIND_GENERIC\n");
346         RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */
347         break;
348     case FC_BIND_PRIMITIVE: /* implicit primitive */
349         TRACE("Implicit primitive handle\n");
350         *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pPrimitiveHandle;
351         break;
352     case FC_CALLBACK_HANDLE: /* implicit callback */
353         TRACE("FC_CALLBACK_HANDLE\n");
354         /* server calls callback procedures only in response to remote call, and most recent
355            binding handle is used. Calling back to a client can potentially result in another
356            callback with different current handle. */
357         *phBinding = I_RpcGetCurrentCallHandle();
358         break;
359     case FC_AUTO_HANDLE: /* implicit auto handle */
360         /* strictly speaking, it isn't necessary to set hBinding here
361          * since it isn't actually used (hence the automatic in its name),
362          * but then why does MIDL generate a valid entry in the
363          * MIDL_STUB_DESC for it? */
364         TRACE("Implicit auto handle\n");
365         *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle;
366         break;
367     default:
368         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
369         RpcRaiseException(RPC_X_BAD_STUB_DATA);
370     }
371     return pFormat;
372 }
373 
374 static void client_free_handle(
375     PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader,
376     PFORMAT_STRING pFormat, handle_t hBinding)
377 {
378     /* binding */
379     switch (pProcHeader->handle_type)
380     {
381     /* explicit binding: parse additional section */
382     case 0:
383         switch (*pFormat) /* handle_type */
384         {
385         case FC_BIND_GENERIC: /* explicit generic */
386             {
387                 const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat;
388                 void *pObject = NULL;
389                 void *pArg;
390                 const GENERIC_BINDING_ROUTINE_PAIR *pGenPair;
391 
392                 TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index);
393 
394                 if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR)
395                     pArg = *(void **)ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
396                 else
397                     pArg = ARG_FROM_OFFSET(pStubMsg->StackTop, pDesc->offset);
398                 memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf);
399                 pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index];
400                 pGenPair->pfnUnbind(pObject, hBinding);
401                 break;
402             }
403         case FC_BIND_CONTEXT: /* explicit context */
404         case FC_BIND_PRIMITIVE: /* explicit primitive */
405             break;
406         default:
407             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
408             RpcRaiseException(RPC_X_BAD_STUB_DATA);
409         }
410         break;
411     case FC_BIND_GENERIC: /* implicit generic */
412         FIXME("FC_BIND_GENERIC\n");
413         RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */
414         break;
415     case FC_CALLBACK_HANDLE: /* implicit callback */
416     case FC_BIND_PRIMITIVE: /* implicit primitive */
417     case FC_AUTO_HANDLE: /* implicit auto handle */
418         break;
419     default:
420         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
421         RpcRaiseException(RPC_X_BAD_STUB_DATA);
422     }
423 }
424 
425 static inline BOOL param_needs_alloc( PARAM_ATTRIBUTES attr )
426 {
427     return attr.IsOut && !attr.IsIn && !attr.IsBasetype && !attr.IsByValue;
428 }
429 
430 static inline BOOL param_is_out_basetype( PARAM_ATTRIBUTES attr )
431 {
432     return attr.IsOut && !attr.IsIn && attr.IsBasetype && attr.IsSimpleRef;
433 }
434 
435 static size_t basetype_arg_size( unsigned char fc )
436 {
437     switch (fc)
438     {
439     case FC_BYTE:
440     case FC_CHAR:
441     case FC_SMALL:
442     case FC_USMALL:
443         return sizeof(char);
444     case FC_WCHAR:
445     case FC_SHORT:
446     case FC_USHORT:
447         return sizeof(short);
448     case FC_LONG:
449     case FC_ULONG:
450     case FC_ENUM16:
451     case FC_ENUM32:
452     case FC_ERROR_STATUS_T:
453         return sizeof(int);
454     case FC_FLOAT:
455         return sizeof(float);
456     case FC_HYPER:
457         return sizeof(LONGLONG);
458     case FC_DOUBLE:
459         return sizeof(double);
460     case FC_INT3264:
461     case FC_UINT3264:
462         return sizeof(INT_PTR);
463     default:
464         FIXME("Unhandled basetype %#x.\n", fc);
465         return 0;
466     }
467 }
468 
469 void client_do_args( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, enum stubless_phase phase,
470                      void **fpu_args, unsigned short number_of_params, unsigned char *pRetVal )
471 {
472     const NDR_PARAM_OIF *params = (const NDR_PARAM_OIF *)pFormat;
473     unsigned int i;
474 
475     for (i = 0; i < number_of_params; i++)
476     {
477         unsigned char *pArg = pStubMsg->StackTop + params[i].stack_offset;
478         PFORMAT_STRING pTypeFormat = (PFORMAT_STRING)&pStubMsg->StubDesc->pFormatTypes[params[i].u.type_offset];
479 
480 #ifdef __x86_64__  /* floats are passed as doubles through varargs functions */
481         float f;
482 
483         if (params[i].attr.IsBasetype &&
484             params[i].u.type_format_char == FC_FLOAT &&
485             !params[i].attr.IsSimpleRef &&
486             !fpu_args)
487         {
488             f = *(double *)pArg;
489             pArg = (unsigned char *)&f;
490         }
491 #endif
492 
493         TRACE("param[%d]: %p type %02x %s\n", i, pArg,
494               params[i].attr.IsBasetype ? params[i].u.type_format_char : *pTypeFormat,
495               debugstr_PROC_PF( params[i].attr ));
496 
497         switch (phase)
498         {
499         case STUBLESS_INITOUT:
500             if (*(unsigned char **)pArg)
501             {
502                 if (param_needs_alloc(params[i].attr))
503                     memset( *(unsigned char **)pArg, 0, calc_arg_size( pStubMsg, pTypeFormat ));
504                 else if (param_is_out_basetype(params[i].attr))
505                     memset( *(unsigned char **)pArg, 0, basetype_arg_size( params[i].u.type_format_char ));
506             }
507             break;
508         case STUBLESS_CALCSIZE:
509             if (params[i].attr.IsSimpleRef && !*(unsigned char **)pArg)
510                 RpcRaiseException(RPC_X_NULL_REF_POINTER);
511             if (params[i].attr.IsIn) call_buffer_sizer(pStubMsg, pArg, &params[i]);
512             break;
513         case STUBLESS_MARSHAL:
514             if (params[i].attr.IsIn) call_marshaller(pStubMsg, pArg, &params[i]);
515             break;
516         case STUBLESS_UNMARSHAL:
517             if (params[i].attr.IsOut)
518             {
519                 if (params[i].attr.IsReturn && pRetVal) pArg = pRetVal;
520                 call_unmarshaller(pStubMsg, &pArg, &params[i], 0);
521             }
522             break;
523         case STUBLESS_FREE:
524             if (!params[i].attr.IsBasetype && params[i].attr.IsOut && !params[i].attr.IsByValue)
525                 NdrClearOutParameters( pStubMsg, pTypeFormat, *(unsigned char **)pArg );
526             break;
527         default:
528             RpcRaiseException(RPC_S_INTERNAL_ERROR);
529         }
530     }
531 }
532 
533 static unsigned int type_stack_size(unsigned char fc)
534 {
535     switch (fc)
536     {
537     case FC_BYTE:
538     case FC_CHAR:
539     case FC_SMALL:
540     case FC_USMALL:
541     case FC_WCHAR:
542     case FC_SHORT:
543     case FC_USHORT:
544     case FC_LONG:
545     case FC_ULONG:
546     case FC_INT3264:
547     case FC_UINT3264:
548     case FC_ENUM16:
549     case FC_ENUM32:
550     case FC_FLOAT:
551     case FC_ERROR_STATUS_T:
552     case FC_IGNORE:
553         return sizeof(void *);
554     case FC_DOUBLE:
555         return sizeof(double);
556     case FC_HYPER:
557         return sizeof(ULONGLONG);
558     default:
559         ERR("invalid base type 0x%x\n", fc);
560         RpcRaiseException(RPC_S_INTERNAL_ERROR);
561     }
562 }
563 
564 static BOOL is_by_value( PFORMAT_STRING format )
565 {
566     switch (*format)
567     {
568     case FC_USER_MARSHAL:
569     case FC_STRUCT:
570     case FC_PSTRUCT:
571     case FC_CSTRUCT:
572     case FC_CPSTRUCT:
573     case FC_CVSTRUCT:
574     case FC_BOGUS_STRUCT:
575         return TRUE;
576     default:
577         return FALSE;
578     }
579 }
580 
581 PFORMAT_STRING convert_old_args( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat,
582                                  unsigned int stack_size, BOOL object_proc,
583                                  void *buffer, unsigned int size, unsigned int *count )
584 {
585     NDR_PARAM_OIF *args = buffer;
586     unsigned int i, stack_offset = object_proc ? sizeof(void *) : 0;
587 
588     for (i = 0; stack_offset < stack_size; i++)
589     {
590         const NDR_PARAM_OI_BASETYPE *param = (const NDR_PARAM_OI_BASETYPE *)pFormat;
591         const NDR_PARAM_OI_OTHER *other = (const NDR_PARAM_OI_OTHER *)pFormat;
592 
593         if (i + 1 > size / sizeof(*args))
594         {
595             FIXME( "%u args not supported\n", i );
596             RpcRaiseException( RPC_S_INTERNAL_ERROR );
597         }
598 
599         args[i].stack_offset = stack_offset;
600         memset( &args[i].attr, 0, sizeof(args[i].attr) );
601 
602         switch (param->param_direction)
603         {
604         case FC_IN_PARAM_BASETYPE:
605             args[i].attr.IsIn = 1;
606             args[i].attr.IsBasetype = 1;
607             break;
608         case FC_RETURN_PARAM_BASETYPE:
609             args[i].attr.IsOut = 1;
610             args[i].attr.IsReturn = 1;
611             args[i].attr.IsBasetype = 1;
612             break;
613         case FC_IN_PARAM:
614             args[i].attr.IsIn = 1;
615             args[i].attr.MustFree = 1;
616             break;
617         case FC_IN_PARAM_NO_FREE_INST:
618             args[i].attr.IsIn = 1;
619             args[i].attr.IsDontCallFreeInst = 1;
620             break;
621         case FC_IN_OUT_PARAM:
622             args[i].attr.IsIn = 1;
623             args[i].attr.IsOut = 1;
624             args[i].attr.MustFree = 1;
625             break;
626         case FC_OUT_PARAM:
627             args[i].attr.IsOut = 1;
628             break;
629         case FC_RETURN_PARAM:
630             args[i].attr.IsOut = 1;
631             args[i].attr.IsReturn = 1;
632             break;
633         }
634         if (args[i].attr.IsBasetype)
635         {
636             args[i].u.type_format_char = param->type_format_char;
637             stack_offset += type_stack_size( param->type_format_char );
638             pFormat += sizeof(NDR_PARAM_OI_BASETYPE);
639         }
640         else
641         {
642             args[i].u.type_offset = other->type_offset;
643             args[i].attr.IsByValue = is_by_value( &pStubMsg->StubDesc->pFormatTypes[other->type_offset] );
644             stack_offset += other->stack_size * sizeof(void *);
645             pFormat += sizeof(NDR_PARAM_OI_OTHER);
646         }
647     }
648     *count = i;
649     return (PFORMAT_STRING)args;
650 }
651 
652 LONG_PTR CDECL DECLSPEC_HIDDEN ndr_client_call( PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat,
653                                                 void **stack_top, void **fpu_stack )
654 {
655     /* pointer to start of stack where arguments start */
656     RPC_MESSAGE rpcMsg;
657     MIDL_STUB_MESSAGE stubMsg;
658     handle_t hBinding = NULL;
659     /* procedure number */
660     unsigned short procedure_number;
661     /* size of stack */
662     unsigned short stack_size;
663     /* number of parameters. optional for client to give it to us */
664     unsigned int number_of_params;
665     /* cache of Oif_flags from v2 procedure header */
666     INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
667     /* cache of extension flags from NDR_PROC_HEADER_EXTS */
668     INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
669     /* header for procedure string */
670     const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
671     /* the value to return to the client from the remote procedure */
672     LONG_PTR RetVal = 0;
673     /* the pointer to the object when in OLE mode */
674     void * This = NULL;
675     PFORMAT_STRING pHandleFormat;
676     /* correlation cache */
677     ULONG_PTR NdrCorrCache[256];
678 
679     TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat);
680 
681     TRACE("NDR Version: 0x%x\n", pStubDesc->Version);
682 
683     if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
684     {
685         const NDR_PROC_HEADER_RPC *header_rpc = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
686         stack_size = header_rpc->stack_size;
687         procedure_number = header_rpc->proc_num;
688         pFormat += sizeof(NDR_PROC_HEADER_RPC);
689     }
690     else
691     {
692         stack_size = pProcHeader->stack_size;
693         procedure_number = pProcHeader->proc_num;
694         pFormat += sizeof(NDR_PROC_HEADER);
695     }
696     TRACE("stack size: 0x%x\n", stack_size);
697     TRACE("proc num: %d\n", procedure_number);
698 
699     /* create the full pointer translation tables, if requested */
700     if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
701         stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT);
702 
703     if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
704     {
705         /* object is always the first argument */
706         This = stack_top[0];
707         NdrProxyInitialize(This, &rpcMsg, &stubMsg, pStubDesc, procedure_number);
708     }
709     else
710         NdrClientInitializeNew(&rpcMsg, &stubMsg, pStubDesc, procedure_number);
711 
712     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
713     TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion);
714 
715     stubMsg.StackTop = (unsigned char *)stack_top;
716     pHandleFormat = pFormat;
717 
718     /* we only need a handle if this isn't an object method */
719     if (!(pProcHeader->Oi_flags & Oi_OBJECT_PROC))
720     {
721         pFormat = client_get_handle(&stubMsg, pProcHeader, pHandleFormat, &hBinding);
722         if (!pFormat) goto done;
723     }
724 
725     if (is_oicf_stubdesc(pStubDesc))  /* -Oicf format */
726     {
727         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
728             (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
729 
730         Oif_flags = pOIFHeader->Oi2Flags;
731         number_of_params = pOIFHeader->number_of_params;
732 
733         pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
734 
735         TRACE("Oif_flags = %s\n", debugstr_INTERPRETER_OPT_FLAGS(Oif_flags) );
736 
737         if (Oif_flags.HasExtensions)
738         {
739             const NDR_PROC_HEADER_EXTS *pExtensions = (const NDR_PROC_HEADER_EXTS *)pFormat;
740             ext_flags = pExtensions->Flags2;
741             pFormat += pExtensions->Size;
742 #ifdef __x86_64__
743             if (pExtensions->Size > sizeof(*pExtensions) && fpu_stack)
744             {
745                 int i;
746                 unsigned short fpu_mask = *(unsigned short *)(pExtensions + 1);
747                 for (i = 0; i < 4; i++, fpu_mask >>= 2)
748                     switch (fpu_mask & 3)
749                     {
750                     case 1: *(float *)&stack_top[i] = *(float *)&fpu_stack[i]; break;
751                     case 2: *(double *)&stack_top[i] = *(double *)&fpu_stack[i]; break;
752                     }
753             }
754 #endif
755         }
756     }
757     else
758     {
759         pFormat = convert_old_args( &stubMsg, pFormat, stack_size,
760                                     pProcHeader->Oi_flags & Oi_OBJECT_PROC,
761                                     /* reuse the correlation cache, it's not needed for v1 format */
762                                     NdrCorrCache, sizeof(NdrCorrCache), &number_of_params );
763     }
764 
765     stubMsg.BufferLength = 0;
766 
767     /* store the RPC flags away */
768     if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
769         rpcMsg.RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
770 
771     /* use alternate memory allocation routines */
772     if (pProcHeader->Oi_flags & Oi_RPCSS_ALLOC_USED)
773         NdrRpcSmSetClientToOsf(&stubMsg);
774 
775     if (Oif_flags.HasPipes)
776     {
777         FIXME("pipes not supported yet\n");
778         RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
779         /* init pipes package */
780         /* NdrPipesInitialize(...) */
781     }
782     if (ext_flags.HasNewCorrDesc)
783     {
784         /* initialize extra correlation package */
785         NdrCorrelationInitialize(&stubMsg, NdrCorrCache, sizeof(NdrCorrCache), 0);
786         if (ext_flags.Unused & 0x2) /* has range on conformance */
787             stubMsg.CorrDespIncrement = 12;
788     }
789 
790     /* order of phases:
791      * 1. INITOUT - zero [out] parameters (proxies only)
792      * 2. CALCSIZE - calculate the buffer size
793      * 3. GETBUFFER - allocate the buffer
794      * 4. MARSHAL - marshal [in] params into the buffer
795      * 5. SENDRECEIVE - send/receive buffer
796      * 6. UNMARSHAL - unmarshal [out] params from buffer
797      * 7. FREE - clear [out] parameters (for proxies, and only on error)
798      */
799     if ((pProcHeader->Oi_flags & Oi_OBJECT_PROC) ||
800         (pProcHeader->Oi_flags & Oi_HAS_COMM_OR_FAULT))
801     {
802         /* 1. INITOUT */
803         if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
804         {
805             TRACE( "INITOUT\n" );
806             client_do_args(&stubMsg, pFormat, STUBLESS_INITOUT, fpu_stack,
807                            number_of_params, (unsigned char *)&RetVal);
808         }
809 
810         __TRY
811         {
812             /* 2. CALCSIZE */
813             TRACE( "CALCSIZE\n" );
814             client_do_args(&stubMsg, pFormat, STUBLESS_CALCSIZE, fpu_stack,
815                            number_of_params, (unsigned char *)&RetVal);
816 
817             /* 3. GETBUFFER */
818             TRACE( "GETBUFFER\n" );
819             if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
820             {
821                 /* allocate the buffer */
822                 NdrProxyGetBuffer(This, &stubMsg);
823             }
824             else
825             {
826                 /* allocate the buffer */
827                 if (Oif_flags.HasPipes)
828                     /* NdrGetPipeBuffer(...) */
829                     FIXME("pipes not supported yet\n");
830                 else
831                 {
832                     if (pProcHeader->handle_type == FC_AUTO_HANDLE)
833 #if 0
834                         NdrNsGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
835 #else
836                     FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
837 #endif
838                     else
839                         NdrGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
840                 }
841             }
842 
843             /* 4. MARSHAL */
844             TRACE( "MARSHAL\n" );
845             client_do_args(&stubMsg, pFormat, STUBLESS_MARSHAL, fpu_stack,
846                            number_of_params, (unsigned char *)&RetVal);
847 
848             /* 5. SENDRECEIVE */
849             TRACE( "SENDRECEIVE\n" );
850             if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
851             {
852                 /* send the [in] params and receive the [out] and [retval]
853                  * params */
854                 NdrProxySendReceive(This, &stubMsg);
855             }
856             else
857             {
858                 /* send the [in] params and receive the [out] and [retval]
859                  * params */
860                 if (Oif_flags.HasPipes)
861                     /* NdrPipesSendReceive(...) */
862                     FIXME("pipes not supported yet\n");
863                 else
864                 {
865                     if (pProcHeader->handle_type == FC_AUTO_HANDLE)
866 #if 0
867                         NdrNsSendReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
868 #else
869                     FIXME("using auto handle - call NdrNsSendReceive when it gets implemented\n");
870 #endif
871                     else
872                         NdrSendReceive(&stubMsg, stubMsg.Buffer);
873                 }
874             }
875 
876             /* convert strings, floating point values and endianness into our
877              * preferred format */
878             if ((rpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
879                 NdrConvert(&stubMsg, pFormat);
880 
881             /* 6. UNMARSHAL */
882             TRACE( "UNMARSHAL\n" );
883             client_do_args(&stubMsg, pFormat, STUBLESS_UNMARSHAL, fpu_stack,
884                            number_of_params, (unsigned char *)&RetVal);
885         }
886         __EXCEPT_ALL
887         {
888             if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
889             {
890                 /* 7. FREE */
891                 TRACE( "FREE\n" );
892                 client_do_args(&stubMsg, pFormat, STUBLESS_FREE, fpu_stack,
893                                number_of_params, (unsigned char *)&RetVal);
894                 RetVal = NdrProxyErrorHandler(GetExceptionCode());
895             }
896             else
897             {
898                 const COMM_FAULT_OFFSETS *comm_fault_offsets = &pStubDesc->CommFaultOffsets[procedure_number];
899                 ULONG *comm_status;
900                 ULONG *fault_status;
901 
902                 TRACE("comm_fault_offsets = {0x%hx, 0x%hx}\n", comm_fault_offsets->CommOffset, comm_fault_offsets->FaultOffset);
903 
904                 if (comm_fault_offsets->CommOffset == -1)
905                     comm_status = (ULONG *)&RetVal;
906                 else if (comm_fault_offsets->CommOffset >= 0)
907                     comm_status = *(ULONG **)ARG_FROM_OFFSET(stubMsg.StackTop, comm_fault_offsets->CommOffset);
908                 else
909                     comm_status = NULL;
910 
911                 if (comm_fault_offsets->FaultOffset == -1)
912                     fault_status = (ULONG *)&RetVal;
913                 else if (comm_fault_offsets->FaultOffset >= 0)
914                     fault_status = *(ULONG **)ARG_FROM_OFFSET(stubMsg.StackTop, comm_fault_offsets->FaultOffset);
915                 else
916                     fault_status = NULL;
917 
918                 NdrMapCommAndFaultStatus(&stubMsg, comm_status, fault_status,
919                                          GetExceptionCode());
920             }
921         }
922         __ENDTRY
923     }
924     else
925     {
926         /* 2. CALCSIZE */
927         TRACE( "CALCSIZE\n" );
928         client_do_args(&stubMsg, pFormat, STUBLESS_CALCSIZE, fpu_stack,
929                        number_of_params, (unsigned char *)&RetVal);
930 
931         /* 3. GETBUFFER */
932         TRACE( "GETBUFFER\n" );
933         if (Oif_flags.HasPipes)
934             /* NdrGetPipeBuffer(...) */
935             FIXME("pipes not supported yet\n");
936         else
937         {
938             if (pProcHeader->handle_type == FC_AUTO_HANDLE)
939 #if 0
940                 NdrNsGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
941 #else
942             FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
943 #endif
944             else
945                 NdrGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding);
946         }
947 
948         /* 4. MARSHAL */
949         TRACE( "MARSHAL\n" );
950         client_do_args(&stubMsg, pFormat, STUBLESS_MARSHAL, fpu_stack,
951                        number_of_params, (unsigned char *)&RetVal);
952 
953         /* 5. SENDRECEIVE */
954         TRACE( "SENDRECEIVE\n" );
955         if (Oif_flags.HasPipes)
956             /* NdrPipesSendReceive(...) */
957             FIXME("pipes not supported yet\n");
958         else
959         {
960             if (pProcHeader->handle_type == FC_AUTO_HANDLE)
961 #if 0
962                 NdrNsSendReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
963 #else
964             FIXME("using auto handle - call NdrNsSendReceive when it gets implemented\n");
965 #endif
966             else
967                 NdrSendReceive(&stubMsg, stubMsg.Buffer);
968         }
969 
970         /* convert strings, floating point values and endianness into our
971          * preferred format */
972         if ((rpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
973             NdrConvert(&stubMsg, pFormat);
974 
975         /* 6. UNMARSHAL */
976         TRACE( "UNMARSHAL\n" );
977         client_do_args(&stubMsg, pFormat, STUBLESS_UNMARSHAL, fpu_stack,
978                        number_of_params, (unsigned char *)&RetVal);
979     }
980 
981     if (ext_flags.HasNewCorrDesc)
982     {
983         /* free extra correlation package */
984         NdrCorrelationFree(&stubMsg);
985     }
986 
987     if (Oif_flags.HasPipes)
988     {
989         /* NdrPipesDone(...) */
990     }
991 
992     /* free the full pointer translation tables */
993     if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
994         NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables);
995 
996     /* free marshalling buffer */
997     if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
998         NdrProxyFreeBuffer(This, &stubMsg);
999     else
1000     {
1001         NdrFreeBuffer(&stubMsg);
1002         client_free_handle(&stubMsg, pProcHeader, pHandleFormat, hBinding);
1003     }
1004 
1005 done:
1006     TRACE("RetVal = 0x%lx\n", RetVal);
1007     return RetVal;
1008 }
1009 
1010 #ifdef __x86_64__
1011 
1012 __ASM_GLOBAL_FUNC( NdrClientCall2,
1013                    "movq %r8,0x18(%rsp)\n\t"
1014                    "movq %r9,0x20(%rsp)\n\t"
1015                    "leaq 0x18(%rsp),%r8\n\t"
1016                    "xorq %r9,%r9\n\t"
1017                    "subq $0x28,%rsp\n\t"
1018                    __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
1019                    "call " __ASM_NAME("ndr_client_call") "\n\t"
1020                    "addq $0x28,%rsp\n\t"
1021                    __ASM_CFI(".cfi_adjust_cfa_offset -0x28\n\t")
1022                    "ret" );
1023 
1024 #else  /* __x86_64__ */
1025 
1026 /***********************************************************************
1027  *            NdrClientCall2 [RPCRT4.@]
1028  */
1029 CLIENT_CALL_RETURN WINAPIV NdrClientCall2( PMIDL_STUB_DESC desc, PFORMAT_STRING format, ... )
1030 {
1031     __ms_va_list args;
1032     LONG_PTR ret;
1033 
1034     __ms_va_start( args, format );
1035     ret = ndr_client_call( desc, format, va_arg( args, void ** ), NULL );
1036     __ms_va_end( args );
1037     return *(CLIENT_CALL_RETURN *)&ret;
1038 }
1039 
1040 #endif  /* __x86_64__ */
1041 
1042 /* Calls a function with the specified arguments, restoring the stack
1043  * properly afterwards as we don't know the calling convention of the
1044  * function */
1045 #if defined __i386__ && defined _MSC_VER
1046 __declspec(naked) LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size)
1047 {
1048     __asm
1049     {
1050         push ebp
1051         mov ebp, esp
1052         push edi            ; Save registers
1053         push esi
1054         mov eax, [ebp+16]   ; Get stack size
1055         sub esp, eax        ; Make room in stack for arguments
1056         and esp, 0xFFFFFFF0
1057         mov edi, esp
1058         mov ecx, eax
1059         mov esi, [ebp+12]
1060         shr ecx, 2
1061         cld
1062         rep movsd           ; Copy dword blocks
1063         call [ebp+8]        ; Call function
1064         lea esp, [ebp-8]    ; Restore stack
1065         pop esi             ; Restore registers
1066         pop edi
1067         pop ebp
1068         ret
1069     }
1070 }
1071 #elif defined __i386__ && defined __GNUC__
1072 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size);
1073 __ASM_GLOBAL_FUNC(call_server_func,
1074     "pushl %ebp\n\t"
1075     __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
1076     __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
1077     "movl %esp,%ebp\n\t"
1078     __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
1079     "pushl %edi\n\t"            /* Save registers */
1080     __ASM_CFI(".cfi_rel_offset %edi,-4\n\t")
1081     "pushl %esi\n\t"
1082     __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
1083     "movl 16(%ebp), %eax\n\t"   /* Get stack size */
1084     "subl %eax, %esp\n\t"       /* Make room in stack for arguments */
1085     "andl $~15, %esp\n\t"	/* Make sure stack has 16-byte alignment for Mac OS X */
1086     "movl %esp, %edi\n\t"
1087     "movl %eax, %ecx\n\t"
1088     "movl 12(%ebp), %esi\n\t"
1089     "shrl $2, %ecx\n\t"         /* divide by 4 */
1090     "cld\n\t"
1091     "rep; movsl\n\t"            /* Copy dword blocks */
1092     "call *8(%ebp)\n\t"         /* Call function */
1093     "leal -8(%ebp), %esp\n\t"   /* Restore stack */
1094     "popl %esi\n\t"             /* Restore registers */
1095     __ASM_CFI(".cfi_same_value %esi\n\t")
1096     "popl %edi\n\t"
1097     __ASM_CFI(".cfi_same_value %edi\n\t")
1098     "popl %ebp\n\t"
1099     __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
1100     __ASM_CFI(".cfi_same_value %ebp\n\t")
1101     "ret" )
1102 #elif defined __x86_64__
1103 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size);
1104 __ASM_GLOBAL_FUNC( call_server_func,
1105                    "pushq %rbp\n\t"
1106                    __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
1107                    __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
1108                    "movq %rsp,%rbp\n\t"
1109                    __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
1110                    "pushq %rsi\n\t"
1111                    __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
1112                    "pushq %rdi\n\t"
1113                    __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
1114                    "movq %rcx,%rax\n\t"   /* function to call */
1115                    "movq $32,%rcx\n\t"    /* allocate max(32,stack_size) bytes of stack space */
1116                    "cmpq %rcx,%r8\n\t"
1117                    "cmovgq %r8,%rcx\n\t"
1118                    "subq %rcx,%rsp\n\t"
1119                    "andq $~15,%rsp\n\t"
1120                    "movq %r8,%rcx\n\t"
1121                    "shrq $3,%rcx\n\t"
1122                    "movq %rsp,%rdi\n\t"
1123                    "movq %rdx,%rsi\n\t"
1124                    "rep; movsq\n\t"       /* copy arguments */
1125                    "movq 0(%rsp),%rcx\n\t"
1126                    "movq 8(%rsp),%rdx\n\t"
1127                    "movq 16(%rsp),%r8\n\t"
1128                    "movq 24(%rsp),%r9\n\t"
1129                    "movq 0(%rsp),%xmm0\n\t"
1130                    "movq 8(%rsp),%xmm1\n\t"
1131                    "movq 16(%rsp),%xmm2\n\t"
1132                    "movq 24(%rsp),%xmm3\n\t"
1133                    "callq *%rax\n\t"
1134                    "leaq -16(%rbp),%rsp\n\t"  /* restore stack */
1135                    "popq %rdi\n\t"
1136                    __ASM_CFI(".cfi_same_value %rdi\n\t")
1137                    "popq %rsi\n\t"
1138                    __ASM_CFI(".cfi_same_value %rsi\n\t")
1139                    __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
1140                    "popq %rbp\n\t"
1141                    __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
1142                    __ASM_CFI(".cfi_same_value %rbp\n\t")
1143                    "ret")
1144 #elif defined __arm__
1145 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char *args, unsigned int stack_size);
1146 __ASM_GLOBAL_FUNC( call_server_func,
1147                    ".arm\n\t"
1148                    "push {r4, r5, LR}\n\t"
1149                    "mov r4, r0\n\t"
1150                    "mov r5, SP\n\t"
1151                    "lsr r3, r2, #2\n\t"
1152                    "cmp r3, #0\n\t"
1153                    "beq 5f\n\t"
1154                    "sub SP, SP, r2\n\t"
1155                    "tst r3, #1\n\t"
1156                    "subeq SP, SP, #4\n\t"
1157                    "1:\tsub r2, r2, #4\n\t"
1158                    "ldr r0, [r1, r2]\n\t"
1159                    "str r0, [SP, r2]\n\t"
1160                    "cmp r2, #0\n\t"
1161                    "bgt 1b\n\t"
1162                    "cmp r3, #1\n\t"
1163                    "bgt 2f\n\t"
1164                    "pop {r0}\n\t"
1165                    "b 5f\n\t"
1166                    "2:\tcmp r3, #2\n\t"
1167                    "bgt 3f\n\t"
1168                    "pop {r0-r1}\n\t"
1169                    "b 5f\n\t"
1170                    "3:\tcmp r3, #3\n\t"
1171                    "bgt 4f\n\t"
1172                    "pop {r0-r2}\n\t"
1173                    "b 5f\n\t"
1174                    "4:\tpop {r0-r3}\n\t"
1175                    "5:\tblx r4\n\t"
1176                    "mov SP, r5\n\t"
1177                    "pop {r4, r5, PC}" )
1178 #else
1179 #warning call_server_func not implemented for your architecture
1180 LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned short stack_size)
1181 {
1182     FIXME("Not implemented for your architecture\n");
1183     return 0;
1184 }
1185 #endif
1186 
1187 static LONG_PTR *stub_do_args(MIDL_STUB_MESSAGE *pStubMsg,
1188                               PFORMAT_STRING pFormat, enum stubless_phase phase,
1189                               unsigned short number_of_params)
1190 {
1191     const NDR_PARAM_OIF *params = (const NDR_PARAM_OIF *)pFormat;
1192     unsigned int i;
1193     LONG_PTR *retval_ptr = NULL;
1194 
1195     for (i = 0; i < number_of_params; i++)
1196     {
1197         unsigned char *pArg = pStubMsg->StackTop + params[i].stack_offset;
1198         const unsigned char *pTypeFormat = &pStubMsg->StubDesc->pFormatTypes[params[i].u.type_offset];
1199 
1200         TRACE("param[%d]: %p -> %p type %02x %s\n", i,
1201               pArg, *(unsigned char **)pArg,
1202               params[i].attr.IsBasetype ? params[i].u.type_format_char : *pTypeFormat,
1203               debugstr_PROC_PF( params[i].attr ));
1204 
1205         switch (phase)
1206         {
1207         case STUBLESS_MARSHAL:
1208             if (params[i].attr.IsOut || params[i].attr.IsReturn)
1209                 call_marshaller(pStubMsg, pArg, &params[i]);
1210             break;
1211         case STUBLESS_MUSTFREE:
1212             if (params[i].attr.MustFree)
1213             {
1214                 call_freer(pStubMsg, pArg, &params[i]);
1215             }
1216             break;
1217         case STUBLESS_FREE:
1218             if (params[i].attr.ServerAllocSize)
1219             {
1220                 HeapFree(GetProcessHeap(), 0, *(void **)pArg);
1221             }
1222             else if (param_needs_alloc(params[i].attr) &&
1223                      (!params[i].attr.MustFree || params[i].attr.IsSimpleRef))
1224             {
1225                 if (*pTypeFormat != FC_BIND_CONTEXT) pStubMsg->pfnFree(*(void **)pArg);
1226             }
1227             break;
1228         case STUBLESS_INITOUT:
1229             if (param_needs_alloc(params[i].attr) && !params[i].attr.ServerAllocSize)
1230             {
1231                 if (*pTypeFormat == FC_BIND_CONTEXT)
1232                 {
1233                     NDR_SCONTEXT ctxt = NdrContextHandleInitialize(pStubMsg, pTypeFormat);
1234                     *(void **)pArg = NDRSContextValue(ctxt);
1235                 }
1236                 else
1237                 {
1238                     DWORD size = calc_arg_size(pStubMsg, pTypeFormat);
1239                     if (size)
1240                     {
1241                         *(void **)pArg = NdrAllocate(pStubMsg, size);
1242                         memset(*(void **)pArg, 0, size);
1243                     }
1244                 }
1245             }
1246             break;
1247         case STUBLESS_UNMARSHAL:
1248             if (params[i].attr.ServerAllocSize)
1249                 *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1250                                            params[i].attr.ServerAllocSize * 8);
1251 
1252             if (params[i].attr.IsIn)
1253                 call_unmarshaller(pStubMsg, &pArg, &params[i], 0);
1254             break;
1255         case STUBLESS_CALCSIZE:
1256             if (params[i].attr.IsOut || params[i].attr.IsReturn)
1257                 call_buffer_sizer(pStubMsg, pArg, &params[i]);
1258             break;
1259         default:
1260             RpcRaiseException(RPC_S_INTERNAL_ERROR);
1261         }
1262         TRACE("\tmemory addr (after): %p -> %p\n", pArg, *(unsigned char **)pArg);
1263 
1264         /* make a note of the address of the return value parameter for later */
1265         if (params[i].attr.IsReturn) retval_ptr = (LONG_PTR *)pArg;
1266     }
1267     return retval_ptr;
1268 }
1269 
1270 /***********************************************************************
1271  *            NdrStubCall2 [RPCRT4.@]
1272  *
1273  * Unmarshals [in] parameters, calls either a method in an object or a server
1274  * function, marshals any [out] parameters and frees any allocated data.
1275  *
1276  * NOTES
1277  *  Used by stubless MIDL-generated code.
1278  */
1279 LONG WINAPI NdrStubCall2(
1280     struct IRpcStubBuffer * pThis,
1281     struct IRpcChannelBuffer * pChannel,
1282     PRPC_MESSAGE pRpcMsg,
1283     DWORD * pdwStubPhase)
1284 {
1285     const MIDL_SERVER_INFO *pServerInfo;
1286     const MIDL_STUB_DESC *pStubDesc;
1287     PFORMAT_STRING pFormat;
1288     MIDL_STUB_MESSAGE stubMsg;
1289     /* pointer to start of stack to pass into stub implementation */
1290     unsigned char * args;
1291     /* size of stack */
1292     unsigned short stack_size;
1293     /* number of parameters. optional for client to give it to us */
1294     unsigned int number_of_params;
1295     /* cache of Oif_flags from v2 procedure header */
1296     INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
1297     /* cache of extension flags from NDR_PROC_HEADER_EXTS */
1298     INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
1299     /* the type of pass we are currently doing */
1300     enum stubless_phase phase;
1301     /* header for procedure string */
1302     const NDR_PROC_HEADER *pProcHeader;
1303     /* location to put retval into */
1304     LONG_PTR *retval_ptr = NULL;
1305     /* correlation cache */
1306     ULONG_PTR NdrCorrCache[256];
1307 
1308     TRACE("pThis %p, pChannel %p, pRpcMsg %p, pdwStubPhase %p\n", pThis, pChannel, pRpcMsg, pdwStubPhase);
1309 
1310     if (pThis)
1311         pServerInfo = CStdStubBuffer_GetServerInfo(pThis);
1312     else
1313         pServerInfo = ((RPC_SERVER_INTERFACE *)pRpcMsg->RpcInterfaceInformation)->InterpreterInfo;
1314 
1315     pStubDesc = pServerInfo->pStubDesc;
1316     pFormat = pServerInfo->ProcString + pServerInfo->FmtStringOffset[pRpcMsg->ProcNum];
1317     pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1318 
1319     TRACE("NDR Version: 0x%x\n", pStubDesc->Version);
1320 
1321     if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1322     {
1323         const NDR_PROC_HEADER_RPC *header_rpc = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1324         stack_size = header_rpc->stack_size;
1325         pFormat += sizeof(NDR_PROC_HEADER_RPC);
1326 
1327     }
1328     else
1329     {
1330         stack_size = pProcHeader->stack_size;
1331         pFormat += sizeof(NDR_PROC_HEADER);
1332     }
1333 
1334     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1335 
1336     /* binding */
1337     switch (pProcHeader->handle_type)
1338     {
1339     /* explicit binding: parse additional section */
1340     case 0:
1341         switch (*pFormat) /* handle_type */
1342         {
1343         case FC_BIND_PRIMITIVE: /* explicit primitive */
1344             pFormat += sizeof(NDR_EHD_PRIMITIVE);
1345             break;
1346         case FC_BIND_GENERIC: /* explicit generic */
1347             pFormat += sizeof(NDR_EHD_GENERIC);
1348             break;
1349         case FC_BIND_CONTEXT: /* explicit context */
1350             pFormat += sizeof(NDR_EHD_CONTEXT);
1351             break;
1352         default:
1353             ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1354             RpcRaiseException(RPC_X_BAD_STUB_DATA);
1355         }
1356         break;
1357     case FC_BIND_GENERIC: /* implicit generic */
1358     case FC_BIND_PRIMITIVE: /* implicit primitive */
1359     case FC_CALLBACK_HANDLE: /* implicit callback */
1360     case FC_AUTO_HANDLE: /* implicit auto handle */
1361         break;
1362     default:
1363         ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type);
1364         RpcRaiseException(RPC_X_BAD_STUB_DATA);
1365     }
1366 
1367     if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
1368         NdrStubInitialize(pRpcMsg, &stubMsg, pStubDesc, pChannel);
1369     else
1370         NdrServerInitializeNew(pRpcMsg, &stubMsg, pStubDesc);
1371 
1372     /* create the full pointer translation tables, if requested */
1373     if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
1374         stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_SERVER);
1375 
1376     /* store the RPC flags away */
1377     if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1378         pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
1379 
1380     /* use alternate memory allocation routines */
1381     if (pProcHeader->Oi_flags & Oi_RPCSS_ALLOC_USED)
1382 #if 0
1383           NdrRpcSsEnableAllocate(&stubMsg);
1384 #else
1385           FIXME("Set RPCSS memory allocation routines\n");
1386 #endif
1387 
1388     TRACE("allocating memory for stack of size %x\n", stack_size);
1389 
1390     args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stack_size);
1391     stubMsg.StackTop = args; /* used by conformance of top-level objects */
1392 
1393     /* add the implicit This pointer as the first arg to the function if we
1394      * are calling an object method */
1395     if (pThis)
1396         *(void **)args = ((CStdStubBuffer *)pThis)->pvServerObject;
1397 
1398     if (is_oicf_stubdesc(pStubDesc))
1399     {
1400         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader = (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
1401 
1402         Oif_flags = pOIFHeader->Oi2Flags;
1403         number_of_params = pOIFHeader->number_of_params;
1404 
1405         pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
1406 
1407         TRACE("Oif_flags = %s\n", debugstr_INTERPRETER_OPT_FLAGS(Oif_flags) );
1408 
1409         if (Oif_flags.HasExtensions)
1410         {
1411             const NDR_PROC_HEADER_EXTS *pExtensions = (const NDR_PROC_HEADER_EXTS *)pFormat;
1412             ext_flags = pExtensions->Flags2;
1413             pFormat += pExtensions->Size;
1414         }
1415 
1416         if (Oif_flags.HasPipes)
1417         {
1418             FIXME("pipes not supported yet\n");
1419             RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
1420             /* init pipes package */
1421             /* NdrPipesInitialize(...) */
1422         }
1423         if (ext_flags.HasNewCorrDesc)
1424         {
1425             /* initialize extra correlation package */
1426             NdrCorrelationInitialize(&stubMsg, NdrCorrCache, sizeof(NdrCorrCache), 0);
1427             if (ext_flags.Unused & 0x2) /* has range on conformance */
1428                 stubMsg.CorrDespIncrement = 12;
1429         }
1430     }
1431     else
1432     {
1433         pFormat = convert_old_args( &stubMsg, pFormat, stack_size,
1434                                     pProcHeader->Oi_flags & Oi_OBJECT_PROC,
1435                                     /* reuse the correlation cache, it's not needed for v1 format */
1436                                     NdrCorrCache, sizeof(NdrCorrCache), &number_of_params );
1437     }
1438 
1439     /* convert strings, floating point values and endianness into our
1440      * preferred format */
1441     if ((pRpcMsg->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
1442         NdrConvert(&stubMsg, pFormat);
1443 
1444     for (phase = STUBLESS_UNMARSHAL; phase <= STUBLESS_FREE; phase++)
1445     {
1446         TRACE("phase = %d\n", phase);
1447         switch (phase)
1448         {
1449         case STUBLESS_CALLSERVER:
1450             /* call the server function */
1451             if (pServerInfo->ThunkTable && pServerInfo->ThunkTable[pRpcMsg->ProcNum])
1452                 pServerInfo->ThunkTable[pRpcMsg->ProcNum](&stubMsg);
1453             else
1454             {
1455                 SERVER_ROUTINE func;
1456                 LONG_PTR retval;
1457 
1458                 if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
1459                 {
1460                     SERVER_ROUTINE *vtbl = *(SERVER_ROUTINE **)((CStdStubBuffer *)pThis)->pvServerObject;
1461                     func = vtbl[pRpcMsg->ProcNum];
1462                 }
1463                 else
1464                     func = pServerInfo->DispatchTable[pRpcMsg->ProcNum];
1465 
1466                 /* FIXME: what happens with return values that don't fit into a single register on x86? */
1467                 retval = call_server_func(func, args, stack_size);
1468 
1469                 if (retval_ptr)
1470                 {
1471                     TRACE("stub implementation returned 0x%lx\n", retval);
1472                     *retval_ptr = retval;
1473                 }
1474                 else
1475                     TRACE("void stub implementation\n");
1476             }
1477 
1478             stubMsg.Buffer = NULL;
1479             stubMsg.BufferLength = 0;
1480 
1481             break;
1482         case STUBLESS_GETBUFFER:
1483             if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
1484                 NdrStubGetBuffer(pThis, pChannel, &stubMsg);
1485             else
1486             {
1487                 RPC_STATUS Status;
1488 
1489                 pRpcMsg->BufferLength = stubMsg.BufferLength;
1490                 /* allocate buffer for [out] and [ret] params */
1491                 Status = I_RpcGetBuffer(pRpcMsg);
1492                 if (Status)
1493                     RpcRaiseException(Status);
1494                 stubMsg.Buffer = pRpcMsg->Buffer;
1495             }
1496             break;
1497         case STUBLESS_UNMARSHAL:
1498         case STUBLESS_INITOUT:
1499         case STUBLESS_CALCSIZE:
1500         case STUBLESS_MARSHAL:
1501         case STUBLESS_MUSTFREE:
1502         case STUBLESS_FREE:
1503             retval_ptr = stub_do_args(&stubMsg, pFormat, phase, number_of_params);
1504             break;
1505         default:
1506             ERR("shouldn't reach here. phase %d\n", phase);
1507             break;
1508         }
1509     }
1510 
1511     pRpcMsg->BufferLength = (unsigned int)(stubMsg.Buffer - (unsigned char *)pRpcMsg->Buffer);
1512 
1513     if (ext_flags.HasNewCorrDesc)
1514     {
1515         /* free extra correlation package */
1516         NdrCorrelationFree(&stubMsg);
1517     }
1518 
1519     if (Oif_flags.HasPipes)
1520     {
1521         /* NdrPipesDone(...) */
1522     }
1523 
1524     /* free the full pointer translation tables */
1525     if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
1526         NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables);
1527 
1528     /* free server function stack */
1529     HeapFree(GetProcessHeap(), 0, args);
1530 
1531     return S_OK;
1532 }
1533 
1534 /***********************************************************************
1535  *            NdrServerCall2 [RPCRT4.@]
1536  */
1537 void WINAPI NdrServerCall2(PRPC_MESSAGE pRpcMsg)
1538 {
1539     DWORD dwPhase;
1540     NdrStubCall2(NULL, NULL, pRpcMsg, &dwPhase);
1541 }
1542 
1543 /***********************************************************************
1544  *            NdrStubCall [RPCRT4.@]
1545  */
1546 LONG WINAPI NdrStubCall( struct IRpcStubBuffer *This, struct IRpcChannelBuffer *channel,
1547                          PRPC_MESSAGE msg, DWORD *phase )
1548 {
1549     return NdrStubCall2( This, channel, msg, phase );
1550 }
1551 
1552 /***********************************************************************
1553  *            NdrServerCall [RPCRT4.@]
1554  */
1555 void WINAPI NdrServerCall( PRPC_MESSAGE msg )
1556 {
1557     DWORD phase;
1558     NdrStubCall( NULL, NULL, msg, &phase );
1559 }
1560 
1561 struct async_call_data
1562 {
1563     MIDL_STUB_MESSAGE *pStubMsg;
1564     const NDR_PROC_HEADER *pProcHeader;
1565     PFORMAT_STRING pHandleFormat;
1566     PFORMAT_STRING pParamFormat;
1567     RPC_BINDING_HANDLE hBinding;
1568     /* size of stack */
1569     unsigned short stack_size;
1570     /* number of parameters. optional for client to give it to us */
1571     unsigned int number_of_params;
1572     /* correlation cache */
1573     ULONG_PTR NdrCorrCache[256];
1574 };
1575 
1576 LONG_PTR CDECL DECLSPEC_HIDDEN ndr_async_client_call( PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat,
1577                                                       void **stack_top )
1578 {
1579     /* pointer to start of stack where arguments start */
1580     PRPC_MESSAGE pRpcMsg;
1581     PMIDL_STUB_MESSAGE pStubMsg;
1582     RPC_ASYNC_STATE *pAsync;
1583     struct async_call_data *async_call_data;
1584     /* procedure number */
1585     unsigned short procedure_number;
1586     /* cache of Oif_flags from v2 procedure header */
1587     INTERPRETER_OPT_FLAGS Oif_flags = { 0 };
1588     /* cache of extension flags from NDR_PROC_HEADER_EXTS */
1589     INTERPRETER_OPT_FLAGS2 ext_flags = { 0 };
1590     /* header for procedure string */
1591     const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0];
1592     RPC_STATUS status;
1593 
1594     TRACE("pStubDesc %p, pFormat %p, ...\n", pStubDesc, pFormat);
1595 
1596     /* Later NDR language versions probably won't be backwards compatible */
1597     if (pStubDesc->Version > 0x50002)
1598     {
1599         FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version);
1600         RpcRaiseException(RPC_X_WRONG_STUB_VERSION);
1601     }
1602 
1603     async_call_data = I_RpcAllocate(sizeof(*async_call_data) + sizeof(MIDL_STUB_MESSAGE) + sizeof(RPC_MESSAGE));
1604     if (!async_call_data) RpcRaiseException(RPC_X_NO_MEMORY);
1605     async_call_data->pProcHeader = pProcHeader;
1606 
1607     async_call_data->pStubMsg = pStubMsg = (PMIDL_STUB_MESSAGE)(async_call_data + 1);
1608     pRpcMsg = (PRPC_MESSAGE)(pStubMsg + 1);
1609 
1610     if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1611     {
1612         const NDR_PROC_HEADER_RPC *header_rpc = (const NDR_PROC_HEADER_RPC *)&pFormat[0];
1613         async_call_data->stack_size = header_rpc->stack_size;
1614         procedure_number = header_rpc->proc_num;
1615         pFormat += sizeof(NDR_PROC_HEADER_RPC);
1616     }
1617     else
1618     {
1619         async_call_data->stack_size = pProcHeader->stack_size;
1620         procedure_number = pProcHeader->proc_num;
1621         pFormat += sizeof(NDR_PROC_HEADER);
1622     }
1623     TRACE("stack size: 0x%x\n", async_call_data->stack_size);
1624     TRACE("proc num: %d\n", procedure_number);
1625 
1626     /* create the full pointer translation tables, if requested */
1627     if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
1628         pStubMsg->FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT);
1629 
1630     if (pProcHeader->Oi_flags & Oi_OBJECT_PROC)
1631     {
1632         ERR("objects not supported\n");
1633         I_RpcFree(async_call_data);
1634         RpcRaiseException(RPC_X_BAD_STUB_DATA);
1635     }
1636 
1637     NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDesc, procedure_number);
1638 
1639     TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags);
1640     TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion);
1641 
1642     /* needed for conformance of top-level objects */
1643     pStubMsg->StackTop = I_RpcAllocate(async_call_data->stack_size);
1644     memcpy(pStubMsg->StackTop, stack_top, async_call_data->stack_size);
1645 
1646     pAsync = *(RPC_ASYNC_STATE **)pStubMsg->StackTop;
1647     pAsync->StubInfo = async_call_data;
1648     async_call_data->pHandleFormat = pFormat;
1649 
1650     pFormat = client_get_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat, &async_call_data->hBinding);
1651     if (!pFormat) goto done;
1652 
1653     if (is_oicf_stubdesc(pStubDesc))
1654     {
1655         const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader =
1656             (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat;
1657 
1658         Oif_flags = pOIFHeader->Oi2Flags;
1659         async_call_data->number_of_params = pOIFHeader->number_of_params;
1660 
1661         pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER);
1662 
1663         TRACE("Oif_flags = %s\n", debugstr_INTERPRETER_OPT_FLAGS(Oif_flags) );
1664 
1665         if (Oif_flags.HasExtensions)
1666         {
1667             const NDR_PROC_HEADER_EXTS *pExtensions =
1668                 (const NDR_PROC_HEADER_EXTS *)pFormat;
1669             ext_flags = pExtensions->Flags2;
1670             pFormat += pExtensions->Size;
1671         }
1672     }
1673     else
1674     {
1675         pFormat = convert_old_args( pStubMsg, pFormat, async_call_data->stack_size,
1676                                     pProcHeader->Oi_flags & Oi_OBJECT_PROC,
1677                                     async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache),
1678                                     &async_call_data->number_of_params );
1679     }
1680 
1681     async_call_data->pParamFormat = pFormat;
1682 
1683     pStubMsg->BufferLength = 0;
1684 
1685     /* store the RPC flags away */
1686     if (pProcHeader->Oi_flags & Oi_HAS_RPCFLAGS)
1687         pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags;
1688 
1689     /* use alternate memory allocation routines */
1690     if (pProcHeader->Oi_flags & Oi_RPCSS_ALLOC_USED)
1691         NdrRpcSmSetClientToOsf(pStubMsg);
1692 
1693     if (Oif_flags.HasPipes)
1694     {
1695         FIXME("pipes not supported yet\n");
1696         RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */
1697         /* init pipes package */
1698         /* NdrPipesInitialize(...) */
1699     }
1700     if (ext_flags.HasNewCorrDesc)
1701     {
1702         /* initialize extra correlation package */
1703         NdrCorrelationInitialize(pStubMsg, async_call_data->NdrCorrCache, sizeof(async_call_data->NdrCorrCache), 0);
1704         if (ext_flags.Unused & 0x2) /* has range on conformance */
1705             pStubMsg->CorrDespIncrement = 12;
1706     }
1707 
1708     /* order of phases:
1709      * 1. CALCSIZE - calculate the buffer size
1710      * 2. GETBUFFER - allocate the buffer
1711      * 3. MARSHAL - marshal [in] params into the buffer
1712      * 4. SENDRECEIVE - send buffer
1713      * Then in NdrpCompleteAsyncClientCall:
1714      * 1. SENDRECEIVE - receive buffer
1715      * 2. UNMARSHAL - unmarshal [out] params from buffer
1716      */
1717 
1718     /* 1. CALCSIZE */
1719     TRACE( "CALCSIZE\n" );
1720     client_do_args(pStubMsg, pFormat, STUBLESS_CALCSIZE, NULL, async_call_data->number_of_params, NULL);
1721 
1722     /* 2. GETBUFFER */
1723     TRACE( "GETBUFFER\n" );
1724     if (Oif_flags.HasPipes)
1725         /* NdrGetPipeBuffer(...) */
1726         FIXME("pipes not supported yet\n");
1727     else
1728     {
1729         if (pProcHeader->handle_type == FC_AUTO_HANDLE)
1730 #if 0
1731             NdrNsGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding);
1732 #else
1733         FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n");
1734 #endif
1735         else
1736             NdrGetBuffer(pStubMsg, pStubMsg->BufferLength, async_call_data->hBinding);
1737     }
1738     pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1739     status = I_RpcAsyncSetHandle(pRpcMsg, pAsync);
1740     if (status != RPC_S_OK)
1741         RpcRaiseException(status);
1742 
1743     /* 3. MARSHAL */
1744     TRACE( "MARSHAL\n" );
1745     client_do_args(pStubMsg, pFormat, STUBLESS_MARSHAL, NULL, async_call_data->number_of_params, NULL);
1746 
1747     /* 4. SENDRECEIVE */
1748     TRACE( "SEND\n" );
1749     pRpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1750     /* send the [in] params only */
1751     if (Oif_flags.HasPipes)
1752         /* NdrPipesSend(...) */
1753         FIXME("pipes not supported yet\n");
1754     else
1755     {
1756         if (pProcHeader->handle_type == FC_AUTO_HANDLE)
1757 #if 0
1758             NdrNsSend(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
1759 #else
1760         FIXME("using auto handle - call NdrNsSend when it gets implemented\n");
1761 #endif
1762         else
1763         {
1764             pStubMsg->RpcMsg->BufferLength = pStubMsg->Buffer - (unsigned char *)pStubMsg->RpcMsg->Buffer;
1765             status = I_RpcSend(pStubMsg->RpcMsg);
1766             if (status != RPC_S_OK)
1767                 RpcRaiseException(status);
1768         }
1769     }
1770 
1771 done:
1772     TRACE("returning 0\n");
1773     return 0;
1774 }
1775 
1776 RPC_STATUS NdrpCompleteAsyncClientCall(RPC_ASYNC_STATE *pAsync, void *Reply)
1777 {
1778     /* pointer to start of stack where arguments start */
1779     PMIDL_STUB_MESSAGE pStubMsg;
1780     struct async_call_data *async_call_data;
1781     /* header for procedure string */
1782     const NDR_PROC_HEADER * pProcHeader;
1783     RPC_STATUS status = RPC_S_OK;
1784 
1785     if (!pAsync->StubInfo)
1786         return RPC_S_INVALID_ASYNC_HANDLE;
1787 
1788     async_call_data = pAsync->StubInfo;
1789     pStubMsg = async_call_data->pStubMsg;
1790     pProcHeader = async_call_data->pProcHeader;
1791 
1792     /* order of phases:
1793      * 1. CALCSIZE - calculate the buffer size
1794      * 2. GETBUFFER - allocate the buffer
1795      * 3. MARSHAL - marshal [in] params into the buffer
1796      * 4. SENDRECEIVE - send buffer
1797      * Then in NdrpCompleteAsyncClientCall:
1798      * 1. SENDRECEIVE - receive buffer
1799      * 2. UNMARSHAL - unmarshal [out] params from buffer
1800      */
1801 
1802     /* 1. SENDRECEIVE */
1803     TRACE( "RECEIVE\n" );
1804     pStubMsg->RpcMsg->RpcFlags |= RPC_BUFFER_ASYNC;
1805     /* receive the [out] params */
1806     if (pProcHeader->handle_type == FC_AUTO_HANDLE)
1807 #if 0
1808         NdrNsReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle);
1809 #else
1810     FIXME("using auto handle - call NdrNsReceive when it gets implemented\n");
1811 #endif
1812     else
1813     {
1814         status = I_RpcReceive(pStubMsg->RpcMsg);
1815         if (status != RPC_S_OK)
1816             goto cleanup;
1817         pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength;
1818         pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer;
1819         pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength;
1820         pStubMsg->Buffer = pStubMsg->BufferStart;
1821     }
1822 
1823     /* convert strings, floating point values and endianness into our
1824      * preferred format */
1825 #if 0
1826     if ((pStubMsg->RpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)
1827         NdrConvert(pStubMsg, pFormat);
1828 #endif
1829 
1830     /* 2. UNMARSHAL */
1831     TRACE( "UNMARSHAL\n" );
1832     client_do_args(pStubMsg, async_call_data->pParamFormat, STUBLESS_UNMARSHAL,
1833                    NULL, async_call_data->number_of_params, Reply);
1834 
1835 cleanup:
1836     if (pStubMsg->fHasNewCorrDesc)
1837     {
1838         /* free extra correlation package */
1839         NdrCorrelationFree(pStubMsg);
1840     }
1841 
1842     /* free the full pointer translation tables */
1843     if (pProcHeader->Oi_flags & Oi_FULL_PTR_USED)
1844         NdrFullPointerXlatFree(pStubMsg->FullPtrXlatTables);
1845 
1846     /* free marshalling buffer */
1847     NdrFreeBuffer(pStubMsg);
1848     client_free_handle(pStubMsg, pProcHeader, async_call_data->pHandleFormat, async_call_data->hBinding);
1849 
1850     I_RpcFree(pStubMsg->StackTop);
1851     I_RpcFree(async_call_data);
1852 
1853     TRACE("-- 0x%x\n", status);
1854     return status;
1855 }
1856 
1857 #ifdef __x86_64__
1858 
1859 __ASM_GLOBAL_FUNC( NdrAsyncClientCall,
1860                    "movq %r8,0x18(%rsp)\n\t"
1861                    "movq %r9,0x20(%rsp)\n\t"
1862                    "leaq 0x18(%rsp),%r8\n\t"
1863                    "subq $0x28,%rsp\n\t"
1864                    __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
1865                    "call " __ASM_NAME("ndr_async_client_call") "\n\t"
1866                    "addq $0x28,%rsp\n\t"
1867                    __ASM_CFI(".cfi_adjust_cfa_offset -0x28\n\t")
1868                    "ret" );
1869 
1870 #else  /* __x86_64__ */
1871 
1872 /***********************************************************************
1873  *            NdrAsyncClientCall [RPCRT4.@]
1874  */
1875 CLIENT_CALL_RETURN WINAPIV NdrAsyncClientCall( PMIDL_STUB_DESC desc, PFORMAT_STRING format, ... )
1876 {
1877     __ms_va_list args;
1878     LONG_PTR ret;
1879 
1880     __ms_va_start( args, format );
1881     ret = ndr_async_client_call( desc, format, va_arg( args, void ** ));
1882     __ms_va_end( args );
1883     return *(CLIENT_CALL_RETURN *)&ret;
1884 }
1885 
1886 #endif  /* __x86_64__ */
1887 
1888 RPCRTAPI LONG RPC_ENTRY NdrAsyncStubCall(struct IRpcStubBuffer* pThis,
1889     struct IRpcChannelBuffer* pChannel, PRPC_MESSAGE pRpcMsg,
1890     DWORD * pdwStubPhase)
1891 {
1892     FIXME("unimplemented, expect crash!\n");
1893     return 0;
1894 }
1895 
1896 void RPC_ENTRY NdrAsyncServerCall(PRPC_MESSAGE pRpcMsg)
1897 {
1898     FIXME("unimplemented, %p\n", pRpcMsg);
1899 }
1900