• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkString.h"
9 #include "include/core/SkTypes.h"
10 #include "modules/skunicode/src/SkUnicode_icu.h"
11 
12 #include <dlfcn.h>
13 
14 #define SK_RUNTIME_ICU_PATHS "libicuuc.so"
15 
SkLoadICULib()16 std::unique_ptr<SkICULib> SkLoadICULib() {
17     static constexpr char const* gLibPaths[] = { SK_RUNTIME_ICU_PATHS };
18 
19     void* dlhnd = nullptr;
20     for (const auto path : gLibPaths) {
21         dlhnd = dlopen(path, RTLD_LAZY);
22         if (dlhnd) {
23             break;
24         }
25     }
26 
27     if (!dlhnd) {
28         SkDEBUGF("ICU loader: failed to open libicuuc.\n");
29         return nullptr;
30     }
31 
32     int icu_ver = -1;
33 
34     bool resolved_required_syms = true;
35 
36     auto resolve_sym = [&](void* hnd, const char name[], bool required = false) -> void* {
37         static constexpr int kMinVer =  44,
38                              kMaxVer = 100;
39 
40         // First call performs a search to determine the actual lib version.
41         // Subsequent calls are pinned to the version found.
42         const auto search_to = icu_ver > 0 ? icu_ver : kMaxVer;
43         icu_ver              = icu_ver > 0 ? icu_ver : kMinVer;
44 
45         for (;;) {
46             const auto sym = SkStringPrintf("%s_%d", name, icu_ver);
47             if (auto* addr = dlsym(dlhnd, sym.c_str())) {
48                 return addr;
49             }
50 
51             if (icu_ver == search_to) {
52                 break;
53             }
54 
55             icu_ver++;
56         }
57 
58         if (required) {
59             resolved_required_syms = false;
60         }
61         return nullptr;
62     };
63 
64     SkICULib lib {};
65 
66     // When using dlsym
67     // *(void**)(&procPtr) = dlsym(self, "proc");
68     // is non-standard, but safe for POSIX. Cannot write
69     // *reinterpret_cast<void**>(&procPtr) = dlsym(self, "proc");
70     // because clang has not implemented DR573. See http://clang.llvm.org/cxx_dr_status.html .
71     #define SKICU_FUNC(fname) *(void**)(&lib.f_##fname) = resolve_sym(dlhnd, #fname, true);
72     SKICU_EMIT_FUNCS
73 
74     *(void**)(&lib.f_ubrk_clone_)     = resolve_sym(dlhnd, "ubrk_clone");
75     *(void**)(&lib.f_ubrk_safeClone_) = resolve_sym(dlhnd, "ubrk_safeClone");
76 
77     if (!resolved_required_syms || (!lib.f_ubrk_clone_ && !lib.f_ubrk_safeClone_)) {
78         SkDEBUGF("ICU loader: failed to resolve required symbols.");
79         dlclose(dlhnd);
80         return nullptr;
81     }
82 
83     return std::make_unique<SkICULib>(lib);
84 }
85