Home | History | Annotate | Download | only in MacOSX-i386
      1 //===-- ABIMacOSX_i386.cpp --------------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "ABIMacOSX_i386.h"
     11 
     12 #include "lldb/Core/ConstString.h"
     13 #include "lldb/Core/Error.h"
     14 #include "lldb/Core/Module.h"
     15 #include "lldb/Core/PluginManager.h"
     16 #include "lldb/Core/RegisterValue.h"
     17 #include "lldb/Core/Scalar.h"
     18 #include "lldb/Core/ValueObjectConstResult.h"
     19 #include "lldb/Symbol/ClangASTContext.h"
     20 #include "lldb/Symbol/UnwindPlan.h"
     21 #include "lldb/Target/Process.h"
     22 #include "lldb/Target/RegisterContext.h"
     23 #include "lldb/Target/Target.h"
     24 #include "lldb/Target/Thread.h"
     25 
     26 #include "llvm/ADT/Triple.h"
     27 
     28 #include <vector>
     29 
     30 using namespace lldb;
     31 using namespace lldb_private;
     32 
     33 enum
     34 {
     35     gcc_eax = 0,
     36     gcc_ecx,
     37     gcc_edx,
     38     gcc_ebx,
     39     gcc_ebp,
     40     gcc_esp,
     41     gcc_esi,
     42     gcc_edi,
     43     gcc_eip,
     44     gcc_eflags
     45 };
     46 
     47 enum
     48 {
     49     dwarf_eax = 0,
     50     dwarf_ecx,
     51     dwarf_edx,
     52     dwarf_ebx,
     53     dwarf_esp,
     54     dwarf_ebp,
     55     dwarf_esi,
     56     dwarf_edi,
     57     dwarf_eip,
     58     dwarf_eflags,
     59     dwarf_stmm0 = 11,
     60     dwarf_stmm1,
     61     dwarf_stmm2,
     62     dwarf_stmm3,
     63     dwarf_stmm4,
     64     dwarf_stmm5,
     65     dwarf_stmm6,
     66     dwarf_stmm7,
     67     dwarf_xmm0 = 21,
     68     dwarf_xmm1,
     69     dwarf_xmm2,
     70     dwarf_xmm3,
     71     dwarf_xmm4,
     72     dwarf_xmm5,
     73     dwarf_xmm6,
     74     dwarf_xmm7,
     75     dwarf_ymm0 = dwarf_xmm0,
     76     dwarf_ymm1 = dwarf_xmm1,
     77     dwarf_ymm2 = dwarf_xmm2,
     78     dwarf_ymm3 = dwarf_xmm3,
     79     dwarf_ymm4 = dwarf_xmm4,
     80     dwarf_ymm5 = dwarf_xmm5,
     81     dwarf_ymm6 = dwarf_xmm6,
     82     dwarf_ymm7 = dwarf_xmm7
     83 };
     84 
     85 enum
     86 {
     87     gdb_eax        =  0,
     88     gdb_ecx        =  1,
     89     gdb_edx        =  2,
     90     gdb_ebx        =  3,
     91     gdb_esp        =  4,
     92     gdb_ebp        =  5,
     93     gdb_esi        =  6,
     94     gdb_edi        =  7,
     95     gdb_eip        =  8,
     96     gdb_eflags     =  9,
     97     gdb_cs         = 10,
     98     gdb_ss         = 11,
     99     gdb_ds         = 12,
    100     gdb_es         = 13,
    101     gdb_fs         = 14,
    102     gdb_gs         = 15,
    103     gdb_stmm0      = 16,
    104     gdb_stmm1      = 17,
    105     gdb_stmm2      = 18,
    106     gdb_stmm3      = 19,
    107     gdb_stmm4      = 20,
    108     gdb_stmm5      = 21,
    109     gdb_stmm6      = 22,
    110     gdb_stmm7      = 23,
    111     gdb_fctrl      = 24,    gdb_fcw     = gdb_fctrl,
    112     gdb_fstat      = 25,    gdb_fsw     = gdb_fstat,
    113     gdb_ftag       = 26,    gdb_ftw     = gdb_ftag,
    114     gdb_fiseg      = 27,    gdb_fpu_cs  = gdb_fiseg,
    115     gdb_fioff      = 28,    gdb_ip      = gdb_fioff,
    116     gdb_foseg      = 29,    gdb_fpu_ds  = gdb_foseg,
    117     gdb_fooff      = 30,    gdb_dp      = gdb_fooff,
    118     gdb_fop        = 31,
    119     gdb_xmm0       = 32,
    120     gdb_xmm1       = 33,
    121     gdb_xmm2       = 34,
    122     gdb_xmm3       = 35,
    123     gdb_xmm4       = 36,
    124     gdb_xmm5       = 37,
    125     gdb_xmm6       = 38,
    126     gdb_xmm7       = 39,
    127     gdb_mxcsr      = 40,
    128     gdb_mm0        = 41,
    129     gdb_mm1        = 42,
    130     gdb_mm2        = 43,
    131     gdb_mm3        = 44,
    132     gdb_mm4        = 45,
    133     gdb_mm5        = 46,
    134     gdb_mm6        = 47,
    135     gdb_mm7        = 48,
    136     gdb_ymm0       = gdb_xmm0,
    137     gdb_ymm1       = gdb_xmm1,
    138     gdb_ymm2       = gdb_xmm2,
    139     gdb_ymm3       = gdb_xmm3,
    140     gdb_ymm4       = gdb_xmm4,
    141     gdb_ymm5       = gdb_xmm5,
    142     gdb_ymm6       = gdb_xmm6,
    143     gdb_ymm7       = gdb_xmm7
    144 };
    145 
    146 
    147 static RegisterInfo g_register_infos[] =
    148 {
    149   //  NAME      ALT      SZ OFF ENCODING         FORMAT                COMPILER              DWARF                 GENERIC                      GDB                   LLDB NATIVE            VALUE REGS    INVALIDATE REGS
    150   //  ======    =======  == === =============    ============          ===================== ===================== ============================ ====================  ====================== ==========    ===============
    151     { "eax",    NULL,    4,  0, eEncodingUint  , eFormatHex          , { gcc_eax             , dwarf_eax           , LLDB_INVALID_REGNUM       , gdb_eax            , LLDB_INVALID_REGNUM },      NULL,              NULL},
    152     { "ebx"   , NULL,    4,  0, eEncodingUint  , eFormatHex          , { gcc_ebx             , dwarf_ebx           , LLDB_INVALID_REGNUM       , gdb_ebx            , LLDB_INVALID_REGNUM },      NULL,              NULL},
    153     { "ecx"   , NULL,    4,  0, eEncodingUint  , eFormatHex          , { gcc_ecx             , dwarf_ecx           , LLDB_REGNUM_GENERIC_ARG4  , gdb_ecx            , LLDB_INVALID_REGNUM },      NULL,              NULL},
    154     { "edx"   , NULL,    4,  0, eEncodingUint  , eFormatHex          , { gcc_edx             , dwarf_edx           , LLDB_REGNUM_GENERIC_ARG3  , gdb_edx            , LLDB_INVALID_REGNUM },      NULL,              NULL},
    155     { "esi"   , NULL,    4,  0, eEncodingUint  , eFormatHex          , { gcc_esi             , dwarf_esi           , LLDB_REGNUM_GENERIC_ARG2  , gdb_esi            , LLDB_INVALID_REGNUM },      NULL,              NULL},
    156     { "edi"   , NULL,    4,  0, eEncodingUint  , eFormatHex          , { gcc_edi             , dwarf_edi           , LLDB_REGNUM_GENERIC_ARG1  , gdb_edi            , LLDB_INVALID_REGNUM },      NULL,              NULL},
    157     { "ebp"   , "fp",    4,  0, eEncodingUint  , eFormatHex          , { gcc_ebp             , dwarf_ebp           , LLDB_REGNUM_GENERIC_FP    , gdb_ebp            , LLDB_INVALID_REGNUM },      NULL,              NULL},
    158     { "esp"   , "sp",    4,  0, eEncodingUint  , eFormatHex          , { gcc_esp             , dwarf_esp           , LLDB_REGNUM_GENERIC_SP    , gdb_esp            , LLDB_INVALID_REGNUM },      NULL,              NULL},
    159     { "eip"   , "pc",    4,  0, eEncodingUint  , eFormatHex          , { gcc_eip             , dwarf_eip           , LLDB_REGNUM_GENERIC_PC    , gdb_eip            , LLDB_INVALID_REGNUM },      NULL,              NULL},
    160     { "eflags", NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_REGNUM_GENERIC_FLAGS , gdb_eflags         , LLDB_INVALID_REGNUM },      NULL,              NULL},
    161     { "cs"    , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_cs             , LLDB_INVALID_REGNUM },      NULL,              NULL},
    162     { "ss"    , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_ss             , LLDB_INVALID_REGNUM },      NULL,              NULL},
    163     { "ds"    , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_ds             , LLDB_INVALID_REGNUM },      NULL,              NULL},
    164     { "es"    , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_es             , LLDB_INVALID_REGNUM },      NULL,              NULL},
    165     { "fs"    , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_fs             , LLDB_INVALID_REGNUM },      NULL,              NULL},
    166     { "gs"    , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_gs             , LLDB_INVALID_REGNUM },      NULL,              NULL},
    167     { "stmm0" , NULL,   10,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm0         , LLDB_INVALID_REGNUM       , gdb_stmm0          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    168     { "stmm1" , NULL,   10,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm1         , LLDB_INVALID_REGNUM       , gdb_stmm1          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    169     { "stmm2" , NULL,   10,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm2         , LLDB_INVALID_REGNUM       , gdb_stmm2          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    170     { "stmm3" , NULL,   10,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm3         , LLDB_INVALID_REGNUM       , gdb_stmm3          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    171     { "stmm4" , NULL,   10,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm4         , LLDB_INVALID_REGNUM       , gdb_stmm4          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    172     { "stmm5" , NULL,   10,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm5         , LLDB_INVALID_REGNUM       , gdb_stmm5          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    173     { "stmm6" , NULL,   10,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm6         , LLDB_INVALID_REGNUM       , gdb_stmm6          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    174     { "stmm7" , NULL,   10,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm7         , LLDB_INVALID_REGNUM       , gdb_stmm7          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    175     { "fctrl" , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_fctrl          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    176     { "fstat" , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_fstat          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    177     { "ftag"  , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_ftag           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    178     { "fiseg" , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_fiseg          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    179     { "fioff" , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_fioff          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    180     { "foseg" , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_foseg          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    181     { "fooff" , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_fooff          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    182     { "fop"   , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_fop            , LLDB_INVALID_REGNUM },      NULL,              NULL},
    183     { "xmm0"  , NULL,   16,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm0          , LLDB_INVALID_REGNUM       , gdb_xmm0           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    184     { "xmm1"  , NULL,   16,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm1          , LLDB_INVALID_REGNUM       , gdb_xmm1           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    185     { "xmm2"  , NULL,   16,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm2          , LLDB_INVALID_REGNUM       , gdb_xmm2           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    186     { "xmm3"  , NULL,   16,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm3          , LLDB_INVALID_REGNUM       , gdb_xmm3           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    187     { "xmm4"  , NULL,   16,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm4          , LLDB_INVALID_REGNUM       , gdb_xmm4           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    188     { "xmm5"  , NULL,   16,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm5          , LLDB_INVALID_REGNUM       , gdb_xmm5           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    189     { "xmm6"  , NULL,   16,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm6          , LLDB_INVALID_REGNUM       , gdb_xmm6           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    190     { "xmm7"  , NULL,   16,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm7          , LLDB_INVALID_REGNUM       , gdb_xmm7           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    191     { "mxcsr" , NULL,    4,  0, eEncodingUint  , eFormatHex          , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM       , gdb_mxcsr          , LLDB_INVALID_REGNUM },      NULL,              NULL},
    192     { "ymm0"  , NULL,   32,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm0          , LLDB_INVALID_REGNUM       , gdb_ymm0           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    193     { "ymm1"  , NULL,   32,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm1          , LLDB_INVALID_REGNUM       , gdb_ymm1           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    194     { "ymm2"  , NULL,   32,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm2          , LLDB_INVALID_REGNUM       , gdb_ymm2           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    195     { "ymm3"  , NULL,   32,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm3          , LLDB_INVALID_REGNUM       , gdb_ymm3           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    196     { "ymm4"  , NULL,   32,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm4          , LLDB_INVALID_REGNUM       , gdb_ymm4           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    197     { "ymm5"  , NULL,   32,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm5          , LLDB_INVALID_REGNUM       , gdb_ymm5           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    198     { "ymm6"  , NULL,   32,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm6          , LLDB_INVALID_REGNUM       , gdb_ymm6           , LLDB_INVALID_REGNUM },      NULL,              NULL},
    199     { "ymm7"  , NULL,   32,  0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm7          , LLDB_INVALID_REGNUM       , gdb_ymm7           , LLDB_INVALID_REGNUM },      NULL,              NULL}
    200 };
    201 
    202 static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo);
    203 static bool g_register_info_names_constified = false;
    204 
    205 const lldb_private::RegisterInfo *
    206 ABIMacOSX_i386::GetRegisterInfoArray (uint32_t &count)
    207 {
    208     // Make the C-string names and alt_names for the register infos into const
    209     // C-string values by having the ConstString unique the names in the global
    210     // constant C-string pool.
    211     if (!g_register_info_names_constified)
    212     {
    213         g_register_info_names_constified = true;
    214         for (uint32_t i=0; i<k_num_register_infos; ++i)
    215         {
    216             if (g_register_infos[i].name)
    217                 g_register_infos[i].name = ConstString(g_register_infos[i].name).GetCString();
    218             if (g_register_infos[i].alt_name)
    219                 g_register_infos[i].alt_name = ConstString(g_register_infos[i].alt_name).GetCString();
    220         }
    221     }
    222     count = k_num_register_infos;
    223     return g_register_infos;
    224 }
    225 
    226 size_t
    227 ABIMacOSX_i386::GetRedZoneSize () const
    228 {
    229     return 0;
    230 }
    231 
    232 //------------------------------------------------------------------
    233 // Static Functions
    234 //------------------------------------------------------------------
    235 ABISP
    236 ABIMacOSX_i386::CreateInstance (const ArchSpec &arch)
    237 {
    238     static ABISP g_abi_sp;
    239     if (arch.GetTriple().getArch() == llvm::Triple::x86)
    240     {
    241         if (!g_abi_sp)
    242             g_abi_sp.reset (new ABIMacOSX_i386);
    243         return g_abi_sp;
    244     }
    245     return ABISP();
    246 }
    247 
    248 bool
    249 ABIMacOSX_i386::PrepareTrivialCall (Thread &thread,
    250                                     addr_t sp,
    251                                     addr_t func_addr,
    252                                     addr_t return_addr,
    253                                     addr_t *arg1_ptr,
    254                                     addr_t *arg2_ptr,
    255                                     addr_t *arg3_ptr,
    256                                     addr_t *arg4_ptr,
    257                                     addr_t *arg5_ptr,
    258                                     addr_t *arg6_ptr) const
    259 {
    260     RegisterContext *reg_ctx = thread.GetRegisterContext().get();
    261     if (!reg_ctx)
    262         return false;
    263     uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
    264     uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
    265 
    266     // When writing a register value down to memory, the register info used
    267     // to write memory just needs to have the correct size of a 32 bit register,
    268     // the actual register it pertains to is not important, just the size needs
    269     // to be correct. Here we use "eax"...
    270     const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax");
    271     if (!reg_info_32)
    272         return false; // TODO this should actually never happen
    273 
    274     // Make room for the argument(s) on the stack
    275 
    276     Error error;
    277     RegisterValue reg_value;
    278 
    279     // Write any arguments onto the stack
    280     if (arg1_ptr)
    281     {
    282         sp -= 4;
    283         if (arg2_ptr)
    284         {
    285             sp -= 4;
    286             if (arg3_ptr)
    287             {
    288                 sp -= 4;
    289                 if (arg4_ptr)
    290                 {
    291                     sp -= 4;
    292                     if (arg5_ptr)
    293                     {
    294                         sp -= 4;
    295                         if (arg6_ptr)
    296                         {
    297                             sp -= 4;
    298                         }
    299                     }
    300                 }
    301             }
    302         }
    303     }
    304 
    305     // Align the SP
    306     sp &= ~(16ull-1ull); // 16-byte alignment
    307 
    308     if (arg1_ptr)
    309     {
    310         reg_value.SetUInt32(*arg1_ptr);
    311         error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
    312                                                      sp,
    313                                                      reg_info_32->byte_size,
    314                                                      reg_value);
    315         if (error.Fail())
    316             return false;
    317 
    318         if (arg2_ptr)
    319         {
    320             reg_value.SetUInt32(*arg2_ptr);
    321             // The register info used to write memory just needs to have the correct
    322             // size of a 32 bit register, the actual register it pertains to is not
    323             // important, just the size needs to be correct. Here we use "eax"...
    324             error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
    325                                                          sp + 4,
    326                                                          reg_info_32->byte_size,
    327                                                          reg_value);
    328             if (error.Fail())
    329                 return false;
    330 
    331             if (arg3_ptr)
    332             {
    333                 reg_value.SetUInt32(*arg3_ptr);
    334                 // The register info used to write memory just needs to have the correct
    335                 // size of a 32 bit register, the actual register it pertains to is not
    336                 // important, just the size needs to be correct. Here we use "eax"...
    337                 error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
    338                                                              sp + 8,
    339                                                              reg_info_32->byte_size,
    340                                                              reg_value);
    341                 if (error.Fail())
    342                     return false;
    343 
    344                 if (arg4_ptr)
    345                 {
    346                     reg_value.SetUInt32(*arg4_ptr);
    347                     // The register info used to write memory just needs to have the correct
    348                     // size of a 32 bit register, the actual register it pertains to is not
    349                     // important, just the size needs to be correct. Here we use "eax"...
    350                     error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
    351                                                                  sp + 12,
    352                                                                  reg_info_32->byte_size,
    353                                                                  reg_value);
    354                     if (error.Fail())
    355                         return false;
    356                     if (arg5_ptr)
    357                     {
    358                         reg_value.SetUInt32(*arg5_ptr);
    359                         // The register info used to write memory just needs to have the correct
    360                         // size of a 32 bit register, the actual register it pertains to is not
    361                         // important, just the size needs to be correct. Here we use "eax"...
    362                         error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
    363                                                                      sp + 16,
    364                                                                      reg_info_32->byte_size,
    365                                                                      reg_value);
    366                         if (error.Fail())
    367                             return false;
    368                         if (arg6_ptr)
    369                         {
    370                             reg_value.SetUInt32(*arg6_ptr);
    371                             // The register info used to write memory just needs to have the correct
    372                             // size of a 32 bit register, the actual register it pertains to is not
    373                             // important, just the size needs to be correct. Here we use "eax"...
    374                             error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
    375                                                                          sp + 20,
    376                                                                          reg_info_32->byte_size,
    377                                                                          reg_value);
    378                             if (error.Fail())
    379                                 return false;
    380                         }
    381                     }
    382                 }
    383             }
    384         }
    385     }
    386 
    387 
    388     // The return address is pushed onto the stack (yes after we just set the
    389     // alignment above!).
    390     sp -= 4;
    391     reg_value.SetUInt32(return_addr);
    392     error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
    393                                                  sp,
    394                                                  reg_info_32->byte_size,
    395                                                  reg_value);
    396     if (error.Fail())
    397         return false;
    398 
    399     // %esp is set to the actual stack value.
    400 
    401     if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_num, sp))
    402         return false;
    403 
    404     // %eip is set to the address of the called function.
    405 
    406     if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_num, func_addr))
    407         return false;
    408 
    409     return true;
    410 }
    411 
    412 bool
    413 ABIMacOSX_i386::PrepareNormalCall (Thread &thread,
    414                                    addr_t sp,
    415                                    addr_t func_addr,
    416                                    addr_t return_addr,
    417                                    ValueList &args) const
    418 {
    419     ExecutionContext exe_ctx (thread.shared_from_this());
    420     RegisterContext *reg_ctx = thread.GetRegisterContext().get();
    421     if (!reg_ctx)
    422         return false;
    423 
    424     Process *process = exe_ctx.GetProcessPtr();
    425     Error error;
    426     uint32_t fp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
    427     uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
    428     uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
    429 
    430     // Do the argument layout
    431 
    432     std::vector <uint32_t> argLayout;   // 4-byte chunks, as discussed in the ABI Function Call Guide
    433 
    434     size_t numArgs = args.GetSize();
    435     size_t index;
    436 
    437     for (index = 0; index < numArgs; ++index)
    438     {
    439         Value *val = args.GetValueAtIndex(index);
    440 
    441         if (!val)
    442             return false;
    443 
    444         switch (val->GetValueType())
    445         {
    446         case Value::eValueTypeScalar:
    447             {
    448                 Scalar &scalar = val->GetScalar();
    449                 switch (scalar.GetType())
    450                 {
    451                 case Scalar::e_void:
    452                     return false;
    453                 case Scalar::e_sint:
    454                 case Scalar::e_uint:
    455                 case Scalar::e_slong:
    456                 case Scalar::e_ulong:
    457                 case Scalar::e_slonglong:
    458                 case Scalar::e_ulonglong:
    459                     {
    460                         uint64_t data = scalar.ULongLong();
    461 
    462                         switch (scalar.GetByteSize())
    463                         {
    464                         default:
    465                             return false;
    466                         case 1:
    467                             argLayout.push_back((uint32_t)(data & 0xffull));
    468                             break;
    469                         case 2:
    470                             argLayout.push_back((uint32_t)(data & 0xffffull));
    471                             break;
    472                         case 4:
    473                             argLayout.push_back((uint32_t)(data & 0xffffffffull));
    474                             break;
    475                         case 8:
    476                             argLayout.push_back((uint32_t)(data & 0xffffffffull));
    477                             argLayout.push_back((uint32_t)(data >> 32));
    478                             break;
    479                         }
    480                     }
    481                     break;
    482                 case Scalar::e_float:
    483                     {
    484                         float data = scalar.Float();
    485                         uint32_t dataRaw = *((uint32_t*)(&data));
    486                         argLayout.push_back(dataRaw);
    487                     }
    488                     break;
    489                 case Scalar::e_double:
    490                     {
    491                         double data = scalar.Double();
    492                         uint32_t *dataRaw = ((uint32_t*)(&data));
    493                         argLayout.push_back(dataRaw[0]);
    494                         argLayout.push_back(dataRaw[1]);
    495                     }
    496                     break;
    497                 case Scalar::e_long_double:
    498                     {
    499                         long double data = scalar.Double();
    500                         uint32_t *dataRaw = ((uint32_t*)(&data));
    501                         while ((argLayout.size() * 4) & 0xf)
    502                             argLayout.push_back(0);
    503                         argLayout.push_back(dataRaw[0]);
    504                         argLayout.push_back(dataRaw[1]);
    505                         argLayout.push_back(dataRaw[2]);
    506                         argLayout.push_back(dataRaw[3]);
    507                     }
    508                     break;
    509                 }
    510             }
    511             break;
    512         case Value::eValueTypeHostAddress:
    513             {
    514                 ClangASTType clang_type (val->GetClangType());
    515                 if (clang_type)
    516                 {
    517                     uint32_t cstr_length = 0;
    518                     if (clang_type.IsCStringType (cstr_length))
    519                     {
    520                         const char *cstr = (const char*)val->GetScalar().ULongLong();
    521                         cstr_length = strlen(cstr);
    522 
    523                         // Push the string onto the stack immediately.
    524 
    525                         sp -= (cstr_length + 1);
    526 
    527                         if (process->WriteMemory(sp, cstr, cstr_length + 1, error) != (cstr_length + 1))
    528                             return false;
    529 
    530                         // Put the address of the string into the argument array.
    531 
    532                         argLayout.push_back((uint32_t)(sp & 0xffffffff));
    533                     }
    534                     else
    535                     {
    536                         return false;
    537                     }
    538                 }
    539                 break;
    540             }
    541             break;
    542         case Value::eValueTypeFileAddress:
    543         case Value::eValueTypeLoadAddress:
    544         default:
    545             return false;
    546         }
    547     }
    548 
    549     // Make room for the arguments on the stack
    550 
    551     sp -= 4 * argLayout.size();
    552 
    553     // Align the SP
    554 
    555     sp &= ~(16ull-1ull); // 16-byte alignment
    556 
    557     // Write the arguments on the stack
    558 
    559     size_t numChunks = argLayout.size();
    560 
    561     for (index = 0; index < numChunks; ++index)
    562         if (process->WriteMemory(sp + (index * 4), &argLayout[index], sizeof(uint32_t), error) != sizeof(uint32_t))
    563             return false;
    564 
    565     // The return address is pushed onto the stack.
    566 
    567     sp -= 4;
    568     uint32_t returnAddressU32 = return_addr;
    569     if (process->WriteMemory (sp, &returnAddressU32, sizeof(returnAddressU32), error) != sizeof(returnAddressU32))
    570         return false;
    571 
    572     // %esp is set to the actual stack value.
    573 
    574     if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp))
    575         return false;
    576 
    577     // %ebp is set to a fake value, in our case 0x0x00000000
    578 
    579     if (!reg_ctx->WriteRegisterFromUnsigned(fp_reg_num, 0x00000000))
    580         return false;
    581 
    582     // %eip is set to the address of the called function.
    583 
    584     if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr))
    585         return false;
    586 
    587     return true;
    588 }
    589 
    590 static bool
    591 ReadIntegerArgument (Scalar           &scalar,
    592                      unsigned int     bit_width,
    593                      bool             is_signed,
    594                      Process          *process,
    595                      addr_t           &current_stack_argument)
    596 {
    597 
    598     uint32_t byte_size = (bit_width + (8-1))/8;
    599     Error error;
    600     if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size, is_signed, scalar, error))
    601     {
    602         current_stack_argument += byte_size;
    603         return true;
    604     }
    605     return false;
    606 }
    607 
    608 bool
    609 ABIMacOSX_i386::GetArgumentValues (Thread &thread,
    610                                    ValueList &values) const
    611 {
    612     unsigned int num_values = values.GetSize();
    613     unsigned int value_index;
    614 
    615     // Get the pointer to the first stack argument so we have a place to start
    616     // when reading data
    617 
    618     RegisterContext *reg_ctx = thread.GetRegisterContext().get();
    619 
    620     if (!reg_ctx)
    621         return false;
    622 
    623     addr_t sp = reg_ctx->GetSP(0);
    624 
    625     if (!sp)
    626         return false;
    627 
    628     addr_t current_stack_argument = sp + 4; // jump over return address
    629 
    630     for (value_index = 0;
    631          value_index < num_values;
    632          ++value_index)
    633     {
    634         Value *value = values.GetValueAtIndex(value_index);
    635 
    636         if (!value)
    637             return false;
    638 
    639         // We currently only support extracting values with Clang QualTypes.
    640         // Do we care about others?
    641         ClangASTType clang_type (value->GetClangType());
    642         if (clang_type)
    643         {
    644             bool is_signed;
    645 
    646             if (clang_type.IsIntegerType (is_signed))
    647             {
    648                 ReadIntegerArgument(value->GetScalar(),
    649                                     clang_type.GetBitSize(),
    650                                     is_signed,
    651                                     thread.GetProcess().get(),
    652                                     current_stack_argument);
    653             }
    654             else if (clang_type.IsPointerType())
    655             {
    656                 ReadIntegerArgument(value->GetScalar(),
    657                                     clang_type.GetBitSize(),
    658                                     false,
    659                                     thread.GetProcess().get(),
    660                                     current_stack_argument);
    661             }
    662         }
    663     }
    664 
    665     return true;
    666 }
    667 
    668 Error
    669 ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp)
    670 {
    671     Error error;
    672     if (!new_value_sp)
    673     {
    674         error.SetErrorString("Empty value object for return value.");
    675         return error;
    676     }
    677 
    678     ClangASTType clang_type = new_value_sp->GetClangType();
    679     if (!clang_type)
    680     {
    681         error.SetErrorString ("Null clang type for return value.");
    682         return error;
    683     }
    684 
    685     Thread *thread = frame_sp->GetThread().get();
    686 
    687     bool is_signed;
    688     uint32_t count;
    689     bool is_complex;
    690 
    691     RegisterContext *reg_ctx = thread->GetRegisterContext().get();
    692 
    693     bool set_it_simple = false;
    694     if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType())
    695     {
    696         DataExtractor data;
    697         size_t num_bytes = new_value_sp->GetData(data);
    698         lldb::offset_t offset = 0;
    699         if (num_bytes <= 8)
    700         {
    701             const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
    702             if (num_bytes <= 4)
    703             {
    704                 uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
    705 
    706                 if (reg_ctx->WriteRegisterFromUnsigned (eax_info, raw_value))
    707                     set_it_simple = true;
    708             }
    709             else
    710             {
    711                 uint32_t raw_value = data.GetMaxU32(&offset, 4);
    712 
    713                 if (reg_ctx->WriteRegisterFromUnsigned (eax_info, raw_value))
    714                 {
    715                     const RegisterInfo *edx_info = reg_ctx->GetRegisterInfoByName("edx", 0);
    716                     uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
    717 
    718                     if (reg_ctx->WriteRegisterFromUnsigned (edx_info, raw_value))
    719                         set_it_simple = true;
    720                 }
    721             }
    722         }
    723         else
    724         {
    725             error.SetErrorString("We don't support returning longer than 64 bit integer values at present.");
    726         }
    727     }
    728     else if (clang_type.IsFloatingPointType (count, is_complex))
    729     {
    730         if (is_complex)
    731             error.SetErrorString ("We don't support returning complex values at present");
    732         else
    733             error.SetErrorString ("We don't support returning float values at present");
    734     }
    735 
    736     if (!set_it_simple)
    737         error.SetErrorString ("We only support setting simple integer return types at present.");
    738 
    739     return error;
    740 }
    741 
    742 ValueObjectSP
    743 ABIMacOSX_i386::GetReturnValueObjectImpl (Thread &thread,
    744                                           ClangASTType &clang_type) const
    745 {
    746     Value value;
    747     ValueObjectSP return_valobj_sp;
    748 
    749     if (!clang_type)
    750         return return_valobj_sp;
    751 
    752     //value.SetContext (Value::eContextTypeClangType, clang_type.GetOpaqueQualType());
    753     value.SetClangType (clang_type);
    754 
    755     RegisterContext *reg_ctx = thread.GetRegisterContext().get();
    756         if (!reg_ctx)
    757         return return_valobj_sp;
    758 
    759     bool is_signed;
    760 
    761     if (clang_type.IsIntegerType (is_signed))
    762     {
    763         size_t bit_width = clang_type.GetBitSize();
    764 
    765         unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
    766         unsigned edx_id = reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
    767 
    768         switch (bit_width)
    769         {
    770             default:
    771             case 128:
    772                 // Scalar can't hold 128-bit literals, so we don't handle this
    773                 return return_valobj_sp;
    774             case 64:
    775                 uint64_t raw_value;
    776                 raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
    777                 raw_value |= (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) & 0xffffffff) << 32;
    778                 if (is_signed)
    779                     value.GetScalar() = (int64_t)raw_value;
    780                 else
    781                     value.GetScalar() = (uint64_t)raw_value;
    782                 break;
    783             case 32:
    784                 if (is_signed)
    785                     value.GetScalar() = (int32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
    786                 else
    787                     value.GetScalar() = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
    788                 break;
    789             case 16:
    790                 if (is_signed)
    791                     value.GetScalar() = (int16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
    792                 else
    793                     value.GetScalar() = (uint16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
    794                 break;
    795             case 8:
    796                 if (is_signed)
    797                     value.GetScalar() = (int8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
    798                 else
    799                     value.GetScalar() = (uint8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
    800                 break;
    801         }
    802     }
    803     else if (clang_type.IsPointerType ())
    804     {
    805         unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
    806         uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
    807         value.GetScalar() = ptr;
    808     }
    809     else
    810     {
    811         // not handled yet
    812         return return_valobj_sp;
    813     }
    814 
    815     // If we get here, we have a valid Value, so make our ValueObject out of it:
    816 
    817     return_valobj_sp = ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),
    818                                                       value,
    819                                                       ConstString(""));
    820     return return_valobj_sp;
    821 }
    822 
    823 bool
    824 ABIMacOSX_i386::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
    825 {
    826     uint32_t reg_kind = unwind_plan.GetRegisterKind();
    827     uint32_t sp_reg_num = LLDB_INVALID_REGNUM;
    828     uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
    829 
    830     switch (reg_kind)
    831     {
    832         case eRegisterKindDWARF:
    833             sp_reg_num = dwarf_esp;
    834             pc_reg_num = dwarf_eip;
    835             break;
    836 
    837         case eRegisterKindGCC:
    838             sp_reg_num = gcc_esp;
    839             pc_reg_num = gcc_eip;
    840             break;
    841 
    842         case eRegisterKindGDB:
    843             sp_reg_num = gdb_esp;
    844             pc_reg_num = gdb_eip;
    845             break;
    846 
    847         case eRegisterKindGeneric:
    848             sp_reg_num = LLDB_REGNUM_GENERIC_SP;
    849             pc_reg_num = LLDB_REGNUM_GENERIC_PC;
    850             break;
    851     }
    852 
    853     if (sp_reg_num == LLDB_INVALID_REGNUM ||
    854         pc_reg_num == LLDB_INVALID_REGNUM)
    855         return false;
    856 
    857     UnwindPlan::RowSP row(new UnwindPlan::Row);
    858     row->SetCFARegister (sp_reg_num);
    859     row->SetCFAOffset (4);
    860     row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
    861     unwind_plan.AppendRow (row);
    862     unwind_plan.SetSourceName ("i386 at-func-entry default");
    863     unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
    864     return true;
    865 }
    866 
    867 bool
    868 ABIMacOSX_i386::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
    869 {
    870     uint32_t fp_reg_num = dwarf_ebp;
    871     uint32_t sp_reg_num = dwarf_esp;
    872     uint32_t pc_reg_num = dwarf_eip;
    873 
    874     UnwindPlan::RowSP row(new UnwindPlan::Row);
    875     const int32_t ptr_size = 4;
    876 
    877     unwind_plan.Clear ();
    878     unwind_plan.SetRegisterKind (eRegisterKindDWARF);
    879     row->SetCFARegister (fp_reg_num);
    880     row->SetCFAOffset (2 * ptr_size);
    881     row->SetOffset (0);
    882 
    883     row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
    884     row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
    885     row->SetRegisterLocationToAtCFAPlusOffset(sp_reg_num, ptr_size *  0, true);
    886 
    887     unwind_plan.AppendRow (row);
    888     unwind_plan.SetSourceName ("i386 default unwind plan");
    889     unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
    890     unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
    891     return true;
    892 }
    893 
    894 bool
    895 ABIMacOSX_i386::RegisterIsVolatile (const RegisterInfo *reg_info)
    896 {
    897     return !RegisterIsCalleeSaved (reg_info);
    898 }
    899 
    900 // v. http://developer.apple.com/library/mac/#documentation/developertools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4
    901 
    902 bool
    903 ABIMacOSX_i386::RegisterIsCalleeSaved (const RegisterInfo *reg_info)
    904 {
    905     if (reg_info)
    906     {
    907         // Saved registers are ebx, ebp, esi, edi, esp, eip
    908         const char *name = reg_info->name;
    909         if (name[0] == 'e')
    910         {
    911             switch (name[1])
    912             {
    913             case 'b':
    914                 if (name[2] == 'x' || name[2] == 'p')
    915                     return name[3] == '\0';
    916                 break;
    917             case 'd':
    918                 if (name[2] == 'i')
    919                     return name[3] == '\0';
    920                 break;
    921             case 'i':
    922                 if (name[2] == 'p')
    923                     return name[3] == '\0';
    924                 break;
    925             case 's':
    926                 if (name[2] == 'i' || name[2] == 'p')
    927                     return name[3] == '\0';
    928                 break;
    929             }
    930         }
    931         if (name[0] == 's' && name[1] == 'p' && name[2] == '\0')   // sp
    932             return true;
    933         if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0')   // fp
    934             return true;
    935         if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0')   // pc
    936             return true;
    937     }
    938     return false;
    939 }
    940 
    941 void
    942 ABIMacOSX_i386::Initialize()
    943 {
    944     PluginManager::RegisterPlugin (GetPluginNameStatic(),
    945                                    "Mac OS X ABI for i386 targets",
    946                                    CreateInstance);
    947 }
    948 
    949 void
    950 ABIMacOSX_i386::Terminate()
    951 {
    952     PluginManager::UnregisterPlugin (CreateInstance);
    953 }
    954 
    955 lldb_private::ConstString
    956 ABIMacOSX_i386::GetPluginNameStatic ()
    957 {
    958     static ConstString g_short_name("abi.macosx-i386");
    959     return g_short_name;
    960 
    961 }
    962 
    963 //------------------------------------------------------------------
    964 // PluginInterface protocol
    965 //------------------------------------------------------------------
    966 lldb_private::ConstString
    967 ABIMacOSX_i386::GetPluginName()
    968 {
    969     return GetPluginNameStatic();
    970 }
    971 
    972 uint32_t
    973 ABIMacOSX_i386::GetPluginVersion()
    974 {
    975     return 1;
    976 }
    977 
    978