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