161dff127SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 361dff127SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 461dff127SAndrew Rist * or more contributor license agreements. See the NOTICE file 561dff127SAndrew Rist * distributed with this work for additional information 661dff127SAndrew Rist * regarding copyright ownership. The ASF licenses this file 761dff127SAndrew Rist * to you under the Apache License, Version 2.0 (the 861dff127SAndrew Rist * "License"); you may not use this file except in compliance 961dff127SAndrew Rist * with the License. You may obtain a copy of the License at 1061dff127SAndrew Rist * 1161dff127SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 1261dff127SAndrew Rist * 1361dff127SAndrew Rist * Unless required by applicable law or agreed to in writing, 1461dff127SAndrew Rist * software distributed under the License is distributed on an 1561dff127SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 1661dff127SAndrew Rist * KIND, either express or implied. See the License for the 1761dff127SAndrew Rist * specific language governing permissions and limitations 1861dff127SAndrew Rist * under the License. 1961dff127SAndrew Rist * 2061dff127SAndrew Rist *************************************************************/ 2161dff127SAndrew Rist 2261dff127SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_bridges.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #if defined OS2 28cdf0e10cSrcweir #define INCL_DOS 29cdf0e10cSrcweir #define INCL_DOSMISC 30cdf0e10cSrcweir #endif 31cdf0e10cSrcweir 32cdf0e10cSrcweir #include "bridges/cpp_uno/shared/vtablefactory.hxx" 33cdf0e10cSrcweir 34cdf0e10cSrcweir #include "guardedarray.hxx" 35cdf0e10cSrcweir 36cdf0e10cSrcweir #include "bridges/cpp_uno/shared/vtables.hxx" 37cdf0e10cSrcweir 38cdf0e10cSrcweir #include "osl/thread.h" 39cdf0e10cSrcweir #include "osl/security.hxx" 40cdf0e10cSrcweir #include "osl/file.hxx" 41cdf0e10cSrcweir #include "osl/diagnose.h" 42cdf0e10cSrcweir #include "osl/mutex.hxx" 43cdf0e10cSrcweir #include "rtl/alloc.h" 44cdf0e10cSrcweir #include "rtl/ustring.hxx" 45cdf0e10cSrcweir #include "sal/types.h" 46cdf0e10cSrcweir #include "typelib/typedescription.hxx" 47cdf0e10cSrcweir 48cdf0e10cSrcweir #include <hash_map> 49cdf0e10cSrcweir #include <new> 50cdf0e10cSrcweir #include <vector> 51cdf0e10cSrcweir 52cdf0e10cSrcweir #if defined SAL_UNX 53cdf0e10cSrcweir #include <unistd.h> 54cdf0e10cSrcweir #include <string.h> 55cdf0e10cSrcweir #include <sys/mman.h> 56cdf0e10cSrcweir #elif defined SAL_W32 57cdf0e10cSrcweir #define WIN32_LEAN_AND_MEAN 58cdf0e10cSrcweir #ifdef _MSC_VER 59cdf0e10cSrcweir #pragma warning(push,1) // disable warnings within system headers 60cdf0e10cSrcweir #endif 61cdf0e10cSrcweir #include <windows.h> 62cdf0e10cSrcweir #ifdef _MSC_VER 63cdf0e10cSrcweir #pragma warning(pop) 64cdf0e10cSrcweir #endif 65cdf0e10cSrcweir #elif defined SAL_OS2 66cdf0e10cSrcweir #define INCL_DOS 67cdf0e10cSrcweir #define INCL_DOSMISC 68cdf0e10cSrcweir #include <os2.h> 69cdf0e10cSrcweir #else 70cdf0e10cSrcweir #error Unsupported platform 71cdf0e10cSrcweir #endif 72cdf0e10cSrcweir 73cdf0e10cSrcweir using bridges::cpp_uno::shared::VtableFactory; 74cdf0e10cSrcweir 75cdf0e10cSrcweir namespace { 76cdf0e10cSrcweir 77cdf0e10cSrcweir extern "C" void * SAL_CALL allocExec(rtl_arena_type *, sal_Size * size) { 78cdf0e10cSrcweir sal_Size pagesize; 79cdf0e10cSrcweir #if defined SAL_UNX 80cdf0e10cSrcweir #if defined FREEBSD || defined NETBSD 81cdf0e10cSrcweir pagesize = getpagesize(); 82cdf0e10cSrcweir #else 83cdf0e10cSrcweir pagesize = sysconf(_SC_PAGESIZE); 84cdf0e10cSrcweir #endif 85cdf0e10cSrcweir #elif defined SAL_W32 86cdf0e10cSrcweir SYSTEM_INFO info; 87cdf0e10cSrcweir GetSystemInfo(&info); 88cdf0e10cSrcweir pagesize = info.dwPageSize; 89cdf0e10cSrcweir #elif defined(SAL_OS2) 90cdf0e10cSrcweir ULONG ulPageSize; 91cdf0e10cSrcweir DosQuerySysInfo(QSV_PAGE_SIZE, QSV_PAGE_SIZE, &ulPageSize, sizeof(ULONG)); 92cdf0e10cSrcweir pagesize = (sal_Size)ulPageSize; 93cdf0e10cSrcweir #else 94cdf0e10cSrcweir #error Unsupported platform 95cdf0e10cSrcweir #endif 96cdf0e10cSrcweir sal_Size n = (*size + (pagesize - 1)) & ~(pagesize - 1); 97cdf0e10cSrcweir void * p; 98cdf0e10cSrcweir #if defined SAL_UNX 99*37f4cb17SJim Jagielski #if defined MACOSX 100*37f4cb17SJim Jagielski p = mmap( 101*37f4cb17SJim Jagielski 0, n, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON | MAP_JIT, -1, 102*37f4cb17SJim Jagielski 0); 103*37f4cb17SJim Jagielski #else 104cdf0e10cSrcweir p = mmap( 105cdf0e10cSrcweir 0, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 106cdf0e10cSrcweir 0); 107cdf0e10cSrcweir if (p == MAP_FAILED) { 108cdf0e10cSrcweir p = 0; 109cdf0e10cSrcweir } 110cdf0e10cSrcweir else if (mprotect (static_cast<char*>(p), n, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) 111cdf0e10cSrcweir { 112cdf0e10cSrcweir munmap (static_cast<char*>(p), n); 113cdf0e10cSrcweir p = 0; 114cdf0e10cSrcweir } 115*37f4cb17SJim Jagielski #endif 116cdf0e10cSrcweir #elif defined SAL_W32 117cdf0e10cSrcweir p = VirtualAlloc(0, n, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 118cdf0e10cSrcweir #elif defined(SAL_OS2) 119cdf0e10cSrcweir p = 0; 120cdf0e10cSrcweir DosAllocMem( &p, n, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY); 121cdf0e10cSrcweir #endif 122cdf0e10cSrcweir if (p != 0) { 123cdf0e10cSrcweir *size = n; 124cdf0e10cSrcweir } 125cdf0e10cSrcweir return p; 126cdf0e10cSrcweir } 127cdf0e10cSrcweir 128cdf0e10cSrcweir extern "C" void SAL_CALL freeExec( 129cdf0e10cSrcweir rtl_arena_type *, void * address, sal_Size size) 130cdf0e10cSrcweir { 131cdf0e10cSrcweir #if defined SAL_UNX 132cdf0e10cSrcweir munmap(static_cast< char * >(address), size); 133cdf0e10cSrcweir #elif defined SAL_W32 134cdf0e10cSrcweir (void) size; // unused 135cdf0e10cSrcweir VirtualFree(address, 0, MEM_RELEASE); 136cdf0e10cSrcweir #elif defined(SAL_OS2) 137cdf0e10cSrcweir (void) DosFreeMem( address); 138cdf0e10cSrcweir #endif 139cdf0e10cSrcweir } 140cdf0e10cSrcweir 141cdf0e10cSrcweir } 142cdf0e10cSrcweir 143cdf0e10cSrcweir class VtableFactory::GuardedBlocks: public std::vector< Block > { 144cdf0e10cSrcweir public: 145cdf0e10cSrcweir GuardedBlocks(VtableFactory const & factory): 146cdf0e10cSrcweir m_factory(factory), m_guarded(true) {} 147cdf0e10cSrcweir 148cdf0e10cSrcweir ~GuardedBlocks(); 149cdf0e10cSrcweir 150cdf0e10cSrcweir void unguard() { m_guarded = false; } 151cdf0e10cSrcweir 152cdf0e10cSrcweir private: 153cdf0e10cSrcweir GuardedBlocks(GuardedBlocks &); // not implemented 154cdf0e10cSrcweir void operator =(GuardedBlocks); // not implemented 155cdf0e10cSrcweir 156cdf0e10cSrcweir VtableFactory const & m_factory; 157cdf0e10cSrcweir bool m_guarded; 158cdf0e10cSrcweir }; 159cdf0e10cSrcweir 160cdf0e10cSrcweir VtableFactory::GuardedBlocks::~GuardedBlocks() { 161cdf0e10cSrcweir if (m_guarded) { 162cdf0e10cSrcweir for (iterator i(begin()); i != end(); ++i) { 163cdf0e10cSrcweir m_factory.freeBlock(*i); 164cdf0e10cSrcweir } 165cdf0e10cSrcweir } 166cdf0e10cSrcweir } 167cdf0e10cSrcweir 168cdf0e10cSrcweir class VtableFactory::BaseOffset { 169cdf0e10cSrcweir public: 170cdf0e10cSrcweir BaseOffset(typelib_InterfaceTypeDescription * type) { calculate(type, 0); } 171cdf0e10cSrcweir 172cdf0e10cSrcweir sal_Int32 getFunctionOffset(rtl::OUString const & name) const 173cdf0e10cSrcweir { return m_map.find(name)->second; } 174cdf0e10cSrcweir 175cdf0e10cSrcweir private: 176cdf0e10cSrcweir sal_Int32 calculate( 177cdf0e10cSrcweir typelib_InterfaceTypeDescription * type, sal_Int32 offset); 178cdf0e10cSrcweir 179cdf0e10cSrcweir typedef std::hash_map< rtl::OUString, sal_Int32, rtl::OUStringHash > Map; 180cdf0e10cSrcweir 181cdf0e10cSrcweir Map m_map; 182cdf0e10cSrcweir }; 183cdf0e10cSrcweir 184cdf0e10cSrcweir sal_Int32 VtableFactory::BaseOffset::calculate( 185cdf0e10cSrcweir typelib_InterfaceTypeDescription * type, sal_Int32 offset) 186cdf0e10cSrcweir { 187cdf0e10cSrcweir rtl::OUString name(type->aBase.pTypeName); 188cdf0e10cSrcweir if (m_map.find(name) == m_map.end()) { 189cdf0e10cSrcweir for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) { 190cdf0e10cSrcweir offset = calculate(type->ppBaseTypes[i], offset); 191cdf0e10cSrcweir } 192cdf0e10cSrcweir m_map.insert(Map::value_type(name, offset)); 193cdf0e10cSrcweir typelib_typedescription_complete( 194cdf0e10cSrcweir reinterpret_cast< typelib_TypeDescription ** >(&type)); 195cdf0e10cSrcweir offset += bridges::cpp_uno::shared::getLocalFunctions(type); 196cdf0e10cSrcweir } 197cdf0e10cSrcweir return offset; 198cdf0e10cSrcweir } 199cdf0e10cSrcweir 200cdf0e10cSrcweir VtableFactory::VtableFactory(): m_arena( 201cdf0e10cSrcweir rtl_arena_create( 202cdf0e10cSrcweir "bridges::cpp_uno::shared::VtableFactory", 203cdf0e10cSrcweir sizeof (void *), // to satisfy alignment requirements 204*37f4cb17SJim Jagielski 0, reinterpret_cast< rtl_arena_type * >( 0 ), allocExec, freeExec, 0)) 205cdf0e10cSrcweir { 206cdf0e10cSrcweir if (m_arena == 0) { 207cdf0e10cSrcweir throw std::bad_alloc(); 208cdf0e10cSrcweir } 209cdf0e10cSrcweir } 210cdf0e10cSrcweir 211cdf0e10cSrcweir VtableFactory::~VtableFactory() { 212cdf0e10cSrcweir { 213cdf0e10cSrcweir osl::MutexGuard guard(m_mutex); 214cdf0e10cSrcweir for (Map::iterator i(m_map.begin()); i != m_map.end(); ++i) { 215cdf0e10cSrcweir for (sal_Int32 j = 0; j < i->second.count; ++j) { 216cdf0e10cSrcweir freeBlock(i->second.blocks[j]); 217cdf0e10cSrcweir } 218cdf0e10cSrcweir delete[] i->second.blocks; 219cdf0e10cSrcweir } 220cdf0e10cSrcweir } 221cdf0e10cSrcweir rtl_arena_destroy(m_arena); 222cdf0e10cSrcweir } 223cdf0e10cSrcweir 224cdf0e10cSrcweir VtableFactory::Vtables VtableFactory::getVtables( 225cdf0e10cSrcweir typelib_InterfaceTypeDescription * type) 226cdf0e10cSrcweir { 227cdf0e10cSrcweir rtl::OUString name(type->aBase.pTypeName); 228cdf0e10cSrcweir osl::MutexGuard guard(m_mutex); 229cdf0e10cSrcweir Map::iterator i(m_map.find(name)); 230cdf0e10cSrcweir if (i == m_map.end()) { 231cdf0e10cSrcweir GuardedBlocks blocks(*this); 232cdf0e10cSrcweir createVtables(blocks, BaseOffset(type), type, true); 233cdf0e10cSrcweir Vtables vtables; 234cdf0e10cSrcweir OSL_ASSERT(blocks.size() <= SAL_MAX_INT32); 235cdf0e10cSrcweir vtables.count = static_cast< sal_Int32 >(blocks.size()); 236cdf0e10cSrcweir bridges::cpp_uno::shared::GuardedArray< Block > guardedBlocks( 237cdf0e10cSrcweir new Block[vtables.count]); 238cdf0e10cSrcweir vtables.blocks = guardedBlocks.get(); 239cdf0e10cSrcweir for (sal_Int32 j = 0; j < vtables.count; ++j) { 240cdf0e10cSrcweir vtables.blocks[j] = blocks[j]; 241cdf0e10cSrcweir } 242cdf0e10cSrcweir i = m_map.insert(Map::value_type(name, vtables)).first; 243cdf0e10cSrcweir guardedBlocks.release(); 244cdf0e10cSrcweir blocks.unguard(); 245cdf0e10cSrcweir } 246cdf0e10cSrcweir return i->second; 247cdf0e10cSrcweir } 248cdf0e10cSrcweir 249cdf0e10cSrcweir #ifdef USE_DOUBLE_MMAP 250cdf0e10cSrcweir bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const 251cdf0e10cSrcweir { 252cdf0e10cSrcweir sal_Size size = getBlockSize(slotCount); 253cdf0e10cSrcweir sal_Size pagesize = sysconf(_SC_PAGESIZE); 254cdf0e10cSrcweir block.size = (size + (pagesize - 1)) & ~(pagesize - 1); 255cdf0e10cSrcweir block.start = block.exec = NULL; 256cdf0e10cSrcweir block.fd = -1; 257cdf0e10cSrcweir 258cdf0e10cSrcweir osl::Security aSecurity; 259cdf0e10cSrcweir rtl::OUString strDirectory; 260cdf0e10cSrcweir rtl::OUString strURLDirectory; 261cdf0e10cSrcweir if (aSecurity.getHomeDir(strURLDirectory)) 262cdf0e10cSrcweir osl::File::getSystemPathFromFileURL(strURLDirectory, strDirectory); 263cdf0e10cSrcweir 2640848378bSHerbert Dürr for (int i = strDirectory.isEmpty() ? 1 : 0; i < 2; ++i) 265cdf0e10cSrcweir { 2660848378bSHerbert Dürr if (strDirectory.isEmpty()) 267cdf0e10cSrcweir strDirectory = rtl::OUString::createFromAscii("/tmp"); 268cdf0e10cSrcweir 269cdf0e10cSrcweir strDirectory += rtl::OUString::createFromAscii("/.execoooXXXXXX"); 270cdf0e10cSrcweir rtl::OString aTmpName = rtl::OUStringToOString(strDirectory, osl_getThreadTextEncoding()); 271cdf0e10cSrcweir char *tmpfname = new char[aTmpName.getLength()+1]; 272cdf0e10cSrcweir strncpy(tmpfname, aTmpName.getStr(), aTmpName.getLength()+1); 273cdf0e10cSrcweir if ((block.fd = mkstemp(tmpfname)) == -1) 274cdf0e10cSrcweir perror("creation of executable memory area failed"); 275cdf0e10cSrcweir if (block.fd == -1) 276cdf0e10cSrcweir { 277cdf0e10cSrcweir delete[] tmpfname; 278cdf0e10cSrcweir break; 279cdf0e10cSrcweir } 280cdf0e10cSrcweir unlink(tmpfname); 281cdf0e10cSrcweir delete[] tmpfname; 282cdf0e10cSrcweir if (ftruncate(block.fd, block.size) == -1) 283cdf0e10cSrcweir { 284cdf0e10cSrcweir perror("truncation of executable memory area failed"); 285cdf0e10cSrcweir close(block.fd); 286cdf0e10cSrcweir block.fd = -1; 287cdf0e10cSrcweir break; 288cdf0e10cSrcweir } 289cdf0e10cSrcweir block.start = mmap(NULL, block.size, PROT_READ | PROT_WRITE, MAP_SHARED, block.fd, 0); 290cdf0e10cSrcweir if (block.start== MAP_FAILED) { 291cdf0e10cSrcweir block.start = 0; 292cdf0e10cSrcweir } 293cdf0e10cSrcweir block.exec = mmap(NULL, block.size, PROT_READ | PROT_EXEC, MAP_SHARED, block.fd, 0); 294cdf0e10cSrcweir if (block.exec == MAP_FAILED) { 295cdf0e10cSrcweir block.exec = 0; 296cdf0e10cSrcweir } 297cdf0e10cSrcweir 298cdf0e10cSrcweir //All good 299cdf0e10cSrcweir if (block.start && block.exec && block.fd != -1) 300cdf0e10cSrcweir break; 301cdf0e10cSrcweir 302cdf0e10cSrcweir freeBlock(block); 303cdf0e10cSrcweir 304cdf0e10cSrcweir strDirectory = rtl::OUString(); 305cdf0e10cSrcweir } 306cdf0e10cSrcweir if (!block.start || !block.exec || block.fd == -1) 307cdf0e10cSrcweir { 308cdf0e10cSrcweir //Fall back to non-doublemmaped allocation 309cdf0e10cSrcweir block.fd = -1; 310cdf0e10cSrcweir block.start = block.exec = rtl_arena_alloc(m_arena, &block.size); 311cdf0e10cSrcweir } 312cdf0e10cSrcweir return (block.start != 0 && block.exec != 0); 313cdf0e10cSrcweir } 314cdf0e10cSrcweir 315cdf0e10cSrcweir void VtableFactory::freeBlock(Block const & block) const { 316cdf0e10cSrcweir //if the double-map failed we were allocated on the arena 317cdf0e10cSrcweir if (block.fd == -1 && block.start == block.exec && block.start != NULL) 318cdf0e10cSrcweir rtl_arena_free(m_arena, block.start, block.size); 319cdf0e10cSrcweir else 320cdf0e10cSrcweir { 321cdf0e10cSrcweir if (block.start) munmap(block.start, block.size); 322cdf0e10cSrcweir if (block.exec) munmap(block.exec, block.size); 323cdf0e10cSrcweir if (block.fd != -1) close(block.fd); 324cdf0e10cSrcweir } 325cdf0e10cSrcweir } 326cdf0e10cSrcweir #else 327cdf0e10cSrcweir bool VtableFactory::createBlock(Block &block, sal_Int32 slotCount) const 328cdf0e10cSrcweir { 329cdf0e10cSrcweir block.size = getBlockSize(slotCount); 330cdf0e10cSrcweir block.start = rtl_arena_alloc(m_arena, &block.size); 331cdf0e10cSrcweir return block.start != 0; 332cdf0e10cSrcweir } 333cdf0e10cSrcweir 334cdf0e10cSrcweir void VtableFactory::freeBlock(Block const & block) const { 335cdf0e10cSrcweir rtl_arena_free(m_arena, block.start, block.size); 336cdf0e10cSrcweir } 337cdf0e10cSrcweir #endif 338cdf0e10cSrcweir 339cdf0e10cSrcweir void VtableFactory::createVtables( 340cdf0e10cSrcweir GuardedBlocks & blocks, BaseOffset const & baseOffset, 341cdf0e10cSrcweir typelib_InterfaceTypeDescription * type, bool includePrimary) const 342cdf0e10cSrcweir { 343cdf0e10cSrcweir if (includePrimary) { 344cdf0e10cSrcweir sal_Int32 slotCount 345cdf0e10cSrcweir = bridges::cpp_uno::shared::getPrimaryFunctions(type); 346cdf0e10cSrcweir Block block; 347cdf0e10cSrcweir if (!createBlock(block, slotCount)) { 348cdf0e10cSrcweir throw std::bad_alloc(); 349cdf0e10cSrcweir } 350cdf0e10cSrcweir try { 351cdf0e10cSrcweir Slot * slots = initializeBlock(block.start, slotCount); 352cdf0e10cSrcweir unsigned char * codeBegin = 353cdf0e10cSrcweir reinterpret_cast< unsigned char * >(slots); 354cdf0e10cSrcweir unsigned char * code = codeBegin; 355cdf0e10cSrcweir sal_Int32 vtableOffset = blocks.size() * sizeof (Slot *); 356cdf0e10cSrcweir for (typelib_InterfaceTypeDescription const * type2 = type; 357cdf0e10cSrcweir type2 != 0; type2 = type2->pBaseTypeDescription) 358cdf0e10cSrcweir { 359cdf0e10cSrcweir code = addLocalFunctions( 360cdf0e10cSrcweir &slots, code, 361cdf0e10cSrcweir #ifdef USE_DOUBLE_MMAP 362cdf0e10cSrcweir sal_IntPtr(block.exec) - sal_IntPtr(block.start), 363cdf0e10cSrcweir #endif 364cdf0e10cSrcweir type2, 365cdf0e10cSrcweir baseOffset.getFunctionOffset(type2->aBase.pTypeName), 366cdf0e10cSrcweir bridges::cpp_uno::shared::getLocalFunctions(type2), 367cdf0e10cSrcweir vtableOffset); 368cdf0e10cSrcweir } 369cdf0e10cSrcweir flushCode(codeBegin, code); 370cdf0e10cSrcweir #ifdef USE_DOUBLE_MMAP 371cdf0e10cSrcweir //Finished generating block, swap writable pointer with executable 372cdf0e10cSrcweir //pointer 373cdf0e10cSrcweir ::std::swap(block.start, block.exec); 374cdf0e10cSrcweir #endif 375cdf0e10cSrcweir blocks.push_back(block); 376cdf0e10cSrcweir } catch (...) { 377cdf0e10cSrcweir freeBlock(block); 378cdf0e10cSrcweir throw; 379cdf0e10cSrcweir } 380cdf0e10cSrcweir } 381cdf0e10cSrcweir for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) { 382cdf0e10cSrcweir createVtables(blocks, baseOffset, type->ppBaseTypes[i], i != 0); 383cdf0e10cSrcweir } 384cdf0e10cSrcweir } 385