LCOV - code coverage report
Current view: top level - src - glibc.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 196 240 81.7 %
Date: 1970-01-01 00:00:01 Functions: 8 8 100.0 %
Branches: 81 130 62.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2019 Andrew Kelley
       3                 :            :  *
       4                 :            :  * This file is part of zig, which is MIT licensed.
       5                 :            :  * See http://opensource.org/licenses/MIT
       6                 :            :  */
       7                 :            : 
       8                 :            : #include "glibc.hpp"
       9                 :            : #include "compiler.hpp"
      10                 :            : #include "cache_hash.hpp"
      11                 :            : #include "codegen.hpp"
      12                 :            : 
      13                 :            : static const ZigGLibCLib glibc_libs[] = {
      14                 :            :     {"c", 6},
      15                 :            :     {"m", 6},
      16                 :            :     {"pthread", 0},
      17                 :            :     {"dl", 2},
      18                 :            :     {"rt", 1},
      19                 :            : };
      20                 :            : 
      21                 :          2 : Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbose) {
      22                 :            :     Error err;
      23                 :            : 
      24                 :          2 :     ZigGLibCAbi *glibc_abi = allocate<ZigGLibCAbi>(1);
      25                 :          2 :     glibc_abi->vers_txt_path = buf_sprintf("%s" OS_SEP "libc" OS_SEP "glibc" OS_SEP "vers.txt", buf_ptr(zig_lib_dir));
      26                 :          2 :     glibc_abi->fns_txt_path = buf_sprintf("%s" OS_SEP "libc" OS_SEP "glibc" OS_SEP "fns.txt", buf_ptr(zig_lib_dir));
      27                 :          2 :     glibc_abi->abi_txt_path = buf_sprintf("%s" OS_SEP "libc" OS_SEP "glibc" OS_SEP "abi.txt", buf_ptr(zig_lib_dir));
      28                 :          2 :     glibc_abi->version_table.init(16);
      29                 :            : 
      30                 :          2 :     Buf *vers_txt_contents = buf_alloc();
      31         [ -  + ]:          2 :     if ((err = os_fetch_file_path(glibc_abi->vers_txt_path, vers_txt_contents))) {
      32         [ #  # ]:          0 :         if (verbose) {
      33                 :          0 :             fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(glibc_abi->vers_txt_path), err_str(err));
      34                 :            :         }
      35                 :          0 :         return err;
      36                 :            :     }
      37                 :          2 :     Buf *fns_txt_contents = buf_alloc();
      38         [ -  + ]:          2 :     if ((err = os_fetch_file_path(glibc_abi->fns_txt_path, fns_txt_contents))) {
      39         [ #  # ]:          0 :         if (verbose) {
      40                 :          0 :             fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(glibc_abi->fns_txt_path), err_str(err));
      41                 :            :         }
      42                 :          0 :         return err;
      43                 :            :     }
      44                 :          2 :     Buf *abi_txt_contents = buf_alloc();
      45         [ -  + ]:          2 :     if ((err = os_fetch_file_path(glibc_abi->abi_txt_path, abi_txt_contents))) {
      46         [ #  # ]:          0 :         if (verbose) {
      47                 :          0 :             fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(glibc_abi->abi_txt_path), err_str(err));
      48                 :            :         }
      49                 :          0 :         return err;
      50                 :            :     }
      51                 :            : 
      52                 :            :     {
      53                 :          2 :         SplitIterator it = memSplit(buf_to_slice(vers_txt_contents), str("\n"));
      54                 :            :         for (;;) {
      55                 :         82 :             Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
      56         [ +  + ]:         82 :             if (!opt_component.is_some) break;
      57                 :         80 :             Buf *ver_buf = buf_create_from_slice(opt_component.value);
      58                 :         80 :             ZigGLibCVersion *this_ver = glibc_abi->all_versions.add_one();
      59         [ -  + ]:         80 :             if ((err = target_parse_glibc_version(this_ver, buf_ptr(ver_buf)))) {
      60         [ #  # ]:          0 :                 if (verbose) {
      61                 :          0 :                     fprintf(stderr, "Unable to parse glibc version '%s': %s\n", buf_ptr(ver_buf), err_str(err));
      62                 :            :                 }
      63                 :          0 :                 return err;
      64                 :            :             }
      65                 :         80 :         }
      66                 :            :     }
      67                 :            :     {
      68                 :          2 :         SplitIterator it = memSplit(buf_to_slice(fns_txt_contents), str("\n"));
      69                 :            :         for (;;) {
      70                 :       7408 :             Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
      71         [ +  + ]:       7408 :             if (!opt_component.is_some) break;
      72                 :       7406 :             SplitIterator line_it = memSplit(opt_component.value, str(" "));
      73                 :       7406 :             Optional<Slice<uint8_t>> opt_fn_name = SplitIterator_next(&line_it);
      74         [ -  + ]:       7406 :             if (!opt_fn_name.is_some) {
      75         [ #  # ]:          0 :                 if (verbose) {
      76                 :          0 :                     fprintf(stderr, "%s: Expected function name\n", buf_ptr(glibc_abi->fns_txt_path));
      77                 :            :                 }
      78                 :          0 :                 return ErrorInvalidFormat;
      79                 :            :             }
      80                 :       7406 :             Optional<Slice<uint8_t>> opt_lib_name = SplitIterator_next(&line_it);
      81         [ -  + ]:       7406 :             if (!opt_lib_name.is_some) {
      82         [ #  # ]:          0 :                 if (verbose) {
      83                 :          0 :                     fprintf(stderr, "%s: Expected lib name\n", buf_ptr(glibc_abi->fns_txt_path));
      84                 :            :                 }
      85                 :          0 :                 return ErrorInvalidFormat;
      86                 :            :             }
      87                 :            : 
      88                 :       7406 :             Buf *this_fn_name = buf_create_from_slice(opt_fn_name.value);
      89                 :       7406 :             Buf *this_lib_name = buf_create_from_slice(opt_lib_name.value);
      90                 :       7406 :             glibc_abi->all_functions.append({ this_fn_name, glibc_lib_find(buf_ptr(this_lib_name)) });
      91                 :       7406 :         }
      92                 :            :     }
      93                 :            :     {
      94                 :          2 :         SplitIterator it = memSplit(buf_to_slice(abi_txt_contents), str("\n"));
      95                 :          2 :         ZigGLibCVerList *ver_list_base = nullptr;
      96                 :            :         for (;;) {
      97         [ +  + ]:         62 :             if (ver_list_base == nullptr) {
      98                 :         32 :                 Optional<Slice<uint8_t>> opt_line = SplitIterator_next_separate(&it);
      99         [ +  + ]:         32 :                 if (!opt_line.is_some) break;
     100                 :            : 
     101                 :         30 :                 ver_list_base = allocate<ZigGLibCVerList>(glibc_abi->all_functions.length);
     102                 :         30 :                 ZigTarget *target = allocate<ZigTarget>(1);
     103                 :         30 :                 SplitIterator line_it = memSplit(opt_line.value, str(" "));
     104                 :            :                 for (;;) {
     105                 :         80 :                     Optional<Slice<uint8_t>> opt_target = SplitIterator_next(&line_it);
     106         [ +  + ]:         80 :                     if (!opt_target.is_some) break;
     107                 :            : 
     108                 :         50 :                     SplitIterator component_it = memSplit(opt_target.value, str("-"));
     109                 :         50 :                     Optional<Slice<uint8_t>> opt_arch = SplitIterator_next(&component_it);
     110                 :         50 :                     assert(opt_arch.is_some);
     111                 :         50 :                     Optional<Slice<uint8_t>> opt_os = SplitIterator_next(&component_it);
     112                 :         50 :                     assert(opt_os.is_some); // it's always "linux" so we ignore it
     113                 :         50 :                     Optional<Slice<uint8_t>> opt_abi = SplitIterator_next(&component_it);
     114                 :         50 :                     assert(opt_abi.is_some);
     115                 :            : 
     116                 :            : 
     117                 :         50 :                     err = target_parse_archsub(&target->arch, &target->sub_arch,
     118                 :         50 :                             (char*)opt_arch.value.ptr, opt_arch.value.len);
     119                 :            :                     // there's no sub arch so we might get an error, but the arch is still populated
     120 [ +  - ][ +  + ]:         50 :                     assert(err == ErrorNone || err == ErrorUnknownArchitecture);
     121                 :            : 
     122                 :         50 :                     target->os = OsLinux;
     123                 :            : 
     124                 :         50 :                     err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len);
     125                 :         50 :                     assert(err == ErrorNone);
     126                 :            : 
     127                 :         50 :                     glibc_abi->version_table.put(target, ver_list_base);
     128                 :         50 :                 }
     129                 :         30 :                 continue;
     130                 :            :             }
     131         [ +  + ]:     111120 :             for (size_t fn_i = 0; fn_i < glibc_abi->all_functions.length; fn_i += 1) {
     132                 :     111090 :                 ZigGLibCVerList *ver_list = &ver_list_base[fn_i];
     133                 :     111090 :                 Optional<Slice<uint8_t>> opt_line = SplitIterator_next_separate(&it);
     134                 :     111090 :                 assert(opt_line.is_some);
     135                 :            : 
     136                 :     111090 :                 SplitIterator line_it = memSplit(opt_line.value, str(" "));
     137                 :            :                 for (;;) {
     138                 :     214920 :                     Optional<Slice<uint8_t>> opt_ver = SplitIterator_next(&line_it);
     139         [ +  + ]:     214920 :                     if (!opt_ver.is_some) break;
     140                 :     103830 :                     assert(ver_list->len < 8); // increase the array len in the type
     141                 :            : 
     142                 :     103830 :                     unsigned long ver_index = strtoul(buf_ptr(buf_create_from_slice(opt_ver.value)), nullptr, 10);
     143                 :     103830 :                     assert(ver_index < 255); // use a bigger integer in the type
     144                 :     103830 :                     ver_list->versions[ver_list->len] = ver_index;
     145                 :     103830 :                     ver_list->len += 1;
     146                 :     103830 :                 }
     147                 :            :             }
     148                 :         30 :             ver_list_base = nullptr;
     149                 :         60 :         }
     150                 :            :     }
     151                 :            : 
     152                 :          2 :     *out_result = glibc_abi;
     153                 :          2 :     return ErrorNone;
     154                 :            : }
     155                 :            : 
     156                 :          2 : Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, const ZigTarget *target,
     157                 :            :         Buf **out_dir, bool verbose)
     158                 :            : {
     159                 :            :     Error err;
     160                 :            : 
     161                 :          2 :     Buf *cache_dir = get_stage1_cache_path();
     162                 :          2 :     CacheHash *cache_hash = allocate<CacheHash>(1);
     163                 :          2 :     Buf *manifest_dir = buf_sprintf("%s" OS_SEP CACHE_HASH_SUBDIR, buf_ptr(cache_dir));
     164                 :          2 :     cache_init(cache_hash, manifest_dir);
     165                 :            : 
     166                 :            :     Buf *compiler_id;
     167         [ -  + ]:          2 :     if ((err = get_compiler_id(&compiler_id))) {
     168         [ #  # ]:          0 :         if (verbose) {
     169                 :          0 :             fprintf(stderr, "unable to get compiler id: %s\n", err_str(err));
     170                 :            :         }
     171                 :          0 :         return err;
     172                 :            :     }
     173                 :          2 :     cache_buf(cache_hash, compiler_id);
     174                 :          2 :     cache_int(cache_hash, target->arch);
     175                 :          2 :     cache_int(cache_hash, target->abi);
     176                 :          2 :     cache_int(cache_hash, target->glibc_version->major);
     177                 :          2 :     cache_int(cache_hash, target->glibc_version->minor);
     178                 :          2 :     cache_int(cache_hash, target->glibc_version->patch);
     179                 :            : 
     180                 :          2 :     Buf digest = BUF_INIT;
     181                 :          2 :     buf_resize(&digest, 0);
     182         [ -  + ]:          2 :     if ((err = cache_hit(cache_hash, &digest))) {
     183                 :            :         // Treat an invalid format error as a cache miss.
     184         [ #  # ]:          0 :         if (err != ErrorInvalidFormat)
     185                 :          0 :             return err;
     186                 :            :     }
     187                 :            :     // We should always get a cache hit because there are no
     188                 :            :     // files in the input hash.
     189                 :          2 :     assert(buf_len(&digest) != 0);
     190                 :            : 
     191                 :          2 :     Buf *dummy_dir = buf_alloc();
     192                 :          2 :     os_path_join(manifest_dir, &digest, dummy_dir);
     193                 :            : 
     194         [ -  + ]:          2 :     if ((err = os_make_path(dummy_dir)))
     195                 :          0 :         return err;
     196                 :            : 
     197                 :          2 :     Buf *test_if_exists_path = buf_alloc();
     198                 :          2 :     os_path_join(dummy_dir, buf_create_from_str("ok"), test_if_exists_path);
     199                 :            : 
     200                 :            :     bool hit;
     201         [ -  + ]:          2 :     if ((err = os_file_exists(test_if_exists_path, &hit)))
     202                 :          0 :         return err;
     203                 :            : 
     204         [ +  + ]:          2 :     if (hit) {
     205                 :          1 :         *out_dir = dummy_dir;
     206                 :          1 :         return ErrorNone;
     207                 :            :     }
     208                 :            : 
     209                 :            : 
     210                 :          1 :     ZigGLibCVerList *ver_list_base = glibc_abi->version_table.get(target);
     211                 :            : 
     212                 :          1 :     uint8_t target_ver_index = 0;
     213         [ +  - ]:         38 :     for (;target_ver_index < glibc_abi->all_versions.length; target_ver_index += 1) {
     214                 :         38 :         const ZigGLibCVersion *this_ver = &glibc_abi->all_versions.at(target_ver_index);
     215 [ +  + ][ +  - ]:         38 :         if (this_ver->major == target->glibc_version->major &&
     216         [ +  - ]:          1 :             this_ver->minor == target->glibc_version->minor &&
     217                 :          1 :             this_ver->patch == target->glibc_version->patch)
     218                 :            :         {
     219                 :          1 :             break;
     220                 :            :         }
     221                 :            :     }
     222         [ -  + ]:          1 :     if (target_ver_index == glibc_abi->all_versions.length) {
     223         [ #  # ]:          0 :         if (verbose) {
     224                 :          0 :             fprintf(stderr, "Unrecognized glibc version: %d.%d.%d\n",
     225                 :          0 :                    target->glibc_version->major,
     226                 :          0 :                    target->glibc_version->minor,
     227                 :          0 :                    target->glibc_version->patch);
     228                 :            :         }
     229                 :          0 :         return ErrorUnknownABI;
     230                 :            :     }
     231                 :            : 
     232                 :          1 :     Buf *map_file_path = buf_sprintf("%s" OS_SEP "all.map", buf_ptr(dummy_dir));
     233                 :          1 :     Buf *map_contents = buf_alloc();
     234                 :            : 
     235         [ +  + ]:         41 :     for (uint8_t ver_i = 0; ver_i < glibc_abi->all_versions.length; ver_i += 1) {
     236                 :         40 :         const ZigGLibCVersion *ver = &glibc_abi->all_versions.at(ver_i);
     237         [ +  + ]:         40 :         if (ver->patch == 0) {
     238                 :         28 :             buf_appendf(map_contents, "GLIBC_%d.%d { };\n", ver->major, ver->minor);
     239                 :            :         } else {
     240                 :         12 :             buf_appendf(map_contents, "GLIBC_%d.%d.%d { };\n", ver->major, ver->minor, ver->patch);
     241                 :            :         }
     242                 :            :     }
     243                 :            : 
     244         [ -  + ]:          1 :     if ((err = os_write_file(map_file_path, map_contents))) {
     245         [ #  # ]:          0 :         if (verbose) {
     246                 :          0 :             fprintf(stderr, "unable to write %s: %s", buf_ptr(map_file_path), err_str(err));
     247                 :            :         }
     248                 :          0 :         return err;
     249                 :            :     }
     250                 :            : 
     251                 :            : 
     252         [ +  + ]:          6 :     for (size_t lib_i = 0; lib_i < array_length(glibc_libs); lib_i += 1) {
     253                 :          5 :         const ZigGLibCLib *lib = &glibc_libs[lib_i];
     254                 :          5 :         Buf *zig_file_path = buf_sprintf("%s" OS_SEP "%s.zig", buf_ptr(dummy_dir), lib->name);
     255                 :          5 :         Buf *zig_body = buf_alloc();
     256                 :          5 :         Buf *zig_footer = buf_alloc();
     257                 :            : 
     258                 :          5 :         buf_appendf(zig_body, "comptime {\n");
     259                 :          5 :         buf_appendf(zig_body, "    asm (\n");
     260                 :            : 
     261         [ +  + ]:      18520 :         for (size_t fn_i = 0; fn_i < glibc_abi->all_functions.length; fn_i += 1) {
     262                 :      18515 :             const ZigGLibCFn *libc_fn = &glibc_abi->all_functions.at(fn_i);
     263         [ +  + ]:      18515 :             if (libc_fn->lib != lib) continue;
     264                 :       3703 :             ZigGLibCVerList *ver_list = &ver_list_base[fn_i];
     265                 :            :             // Pick the default symbol version:
     266                 :            :             // - If there are no versions, don't emit it
     267                 :            :             // - Take the greatest one <= than the target one
     268                 :            :             // - If none of them is <= than the
     269                 :            :             //   specified one don't pick any default version 
     270         [ +  + ]:       3703 :             if (ver_list->len == 0) continue;
     271                 :       3390 :             uint8_t chosen_def_ver_index = 255;
     272         [ +  + ]:       6843 :             for (uint8_t ver_i = 0; ver_i < ver_list->len; ver_i += 1) {
     273                 :       3453 :                 uint8_t ver_index = ver_list->versions[ver_i];
     274 [ +  + ][ +  + ]:       3453 :                 if ((chosen_def_ver_index == 255 || ver_index > chosen_def_ver_index) &&
                 [ +  + ]
     275                 :            :                     target_ver_index >= ver_index)
     276                 :            :                 {
     277                 :       3345 :                     chosen_def_ver_index = ver_index;
     278                 :            :                 }
     279                 :            :             }
     280         [ +  + ]:       6843 :             for (uint8_t ver_i = 0; ver_i < ver_list->len; ver_i += 1) {
     281                 :       3453 :                 uint8_t ver_index = ver_list->versions[ver_i];
     282                 :            : 
     283                 :            :                 Buf *stub_name;
     284                 :       3453 :                 const ZigGLibCVersion *ver = &glibc_abi->all_versions.at(ver_index);
     285                 :       3453 :                 const char *sym_name = buf_ptr(libc_fn->name);
     286         [ +  + ]:       3453 :                 if (ver->patch == 0) {
     287                 :       1172 :                     stub_name = buf_sprintf("%s_%d_%d", sym_name, ver->major, ver->minor);
     288                 :            :                 } else {
     289                 :       2281 :                     stub_name = buf_sprintf("%s_%d_%d_%d", sym_name, ver->major, ver->minor, ver->patch);
     290                 :            :                 }
     291                 :            : 
     292                 :       3453 :                 buf_appendf(zig_footer, "export fn %s() void {}\n", buf_ptr(stub_name));
     293                 :            : 
     294                 :            :                 // Default symbol version definition vs normal symbol version definition
     295         [ +  + ]:       3370 :                 const char *at_sign_str = (chosen_def_ver_index != 255 &&
     296         [ +  + ]:       6823 :                         ver_index == chosen_def_ver_index) ? "@@" : "@";
     297         [ +  + ]:       3453 :                 if (ver->patch == 0) {
     298                 :       1172 :                     buf_appendf(zig_body, "        \\\\ .symver %s, %s%sGLIBC_%d.%d\n",
     299                 :       1172 :                             buf_ptr(stub_name), sym_name, at_sign_str, ver->major, ver->minor);
     300                 :            :                 } else {
     301                 :       2281 :                     buf_appendf(zig_body, "        \\\\ .symver %s, %s%sGLIBC_%d.%d.%d\n",
     302                 :       2281 :                             buf_ptr(stub_name), sym_name, at_sign_str, ver->major, ver->minor, ver->patch);
     303                 :            :                 }
     304                 :            :                 // Hide the stub to keep the symbol table clean
     305                 :       3453 :                 buf_appendf(zig_body, "        \\\\ .hidden %s\n", buf_ptr(stub_name));
     306                 :            :             }
     307                 :            :         }
     308                 :            : 
     309                 :          5 :         buf_appendf(zig_body, "    );\n");
     310                 :          5 :         buf_appendf(zig_body, "}\n");
     311                 :          5 :         buf_append_buf(zig_body, zig_footer);
     312                 :            : 
     313         [ -  + ]:          5 :         if ((err = os_write_file(zig_file_path, zig_body))) {
     314         [ #  # ]:          0 :             if (verbose) {
     315                 :          0 :                 fprintf(stderr, "unable to write %s: %s", buf_ptr(zig_file_path), err_str(err));
     316                 :            :             }
     317                 :          0 :             return err;
     318                 :            :         }
     319                 :            : 
     320                 :          5 :         CodeGen *child_gen = create_child_codegen(g, zig_file_path, OutTypeLib, nullptr);
     321                 :          5 :         codegen_set_out_name(child_gen, buf_create_from_str(lib->name));
     322                 :          5 :         codegen_set_lib_version(child_gen, lib->sover, 0, 0);
     323                 :          5 :         child_gen->is_dynamic = true;
     324                 :          5 :         child_gen->is_dummy_so = true;
     325                 :          5 :         child_gen->version_script_path = map_file_path; 
     326                 :          5 :         child_gen->enable_cache = false;
     327                 :          5 :         child_gen->output_dir = dummy_dir;
     328                 :          5 :         codegen_build_and_link(child_gen);
     329                 :            :     }
     330                 :            : 
     331         [ -  + ]:          1 :     if ((err = os_write_file(test_if_exists_path, buf_alloc()))) {
     332         [ #  # ]:          0 :         if (verbose) {
     333                 :          0 :             fprintf(stderr, "unable to write %s: %s", buf_ptr(test_if_exists_path), err_str(err));
     334                 :            :         }
     335                 :          0 :         return err;
     336                 :            :     }
     337                 :          1 :     *out_dir = dummy_dir;
     338                 :          2 :     return ErrorNone;
     339                 :            : }
     340                 :            : 
     341                 :         71 : uint32_t hash_glibc_target(const ZigTarget *x) {
     342                 :         71 :     return x->arch * 3250106448 +
     343                 :        142 :         x->os * 542534372 +
     344                 :         71 :         x->abi * 59162639;
     345                 :            : }
     346                 :            : 
     347                 :        113 : bool eql_glibc_target(const ZigTarget *a, const ZigTarget *b) {
     348         [ +  - ]:         21 :     return a->arch == b->arch &&
     349 [ +  + ][ +  + ]:        134 :         a->os == b->os &&
     350                 :        113 :         a->abi == b->abi;
     351                 :            : }
     352                 :            : 
     353                 :            : #ifdef ZIG_OS_LINUX
     354                 :            : #include <unistd.h>
     355                 :         26 : Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver) {
     356                 :         26 :     Buf *self_libc_path = get_self_libc_path();
     357         [ -  + ]:         26 :     if (self_libc_path == nullptr) {
     358                 :            :         // TODO There is still more we could do to detect the native glibc version. For example,
     359                 :            :         // we could look at the ELF file of `/usr/bin/env`, find `libc.so.6`, and then `readlink`
     360                 :            :         // to find out the glibc version. This is relevant for the static zig builds distributed
     361                 :            :         // on the download page, since the above detection based on zig's own dynamic linking
     362                 :            :         // will not work.
     363                 :            : 
     364                 :          0 :         return ErrorUnknownABI;
     365                 :            :     }
     366                 :         26 :     Buf *link_name = buf_alloc();
     367                 :         26 :     buf_resize(link_name, 4096);
     368                 :         26 :     ssize_t amt = readlink(buf_ptr(self_libc_path), buf_ptr(link_name), buf_len(link_name));
     369         [ -  + ]:         26 :     if (amt == -1) {
     370                 :          0 :         return ErrorUnknownABI;
     371                 :            :     }
     372                 :         26 :     buf_resize(link_name, amt);
     373 [ -  + ][ -  + ]:         26 :     if (!buf_starts_with_str(link_name, "libc-") || !buf_ends_with_str(link_name, ".so")) {
                 [ +  - ]
     374                 :          0 :         return ErrorUnknownABI;
     375                 :            :     }
     376                 :            :     // example: "libc-2.3.4.so"
     377                 :            :     // example: "libc-2.27.so"
     378                 :         26 :     buf_resize(link_name, buf_len(link_name) - 3); // chop off ".so"
     379                 :         26 :     glibc_ver->major = 2;
     380                 :         26 :     glibc_ver->minor = 0;
     381                 :         26 :     glibc_ver->patch = 0;
     382                 :         26 :     return target_parse_glibc_version(glibc_ver, buf_ptr(link_name) + 5);
     383                 :            : }
     384                 :            : #else
     385                 :            : Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver) {
     386                 :            :     return ErrorUnknownABI;
     387                 :            : }
     388                 :            : #endif
     389                 :            : 
     390                 :          2 : size_t glibc_lib_count(void) {
     391                 :          2 :     return array_length(glibc_libs);
     392                 :            : }
     393                 :            : 
     394                 :         10 : const ZigGLibCLib *glibc_lib_enum(size_t index) {
     395                 :         10 :     assert(index < array_length(glibc_libs));
     396                 :         10 :     return &glibc_libs[index];
     397                 :            : }
     398                 :            : 
     399                 :       7406 : const ZigGLibCLib *glibc_lib_find(const char *name) {
     400         [ +  - ]:      10438 :     for (size_t i = 0; i < array_length(glibc_libs); i += 1) {
     401         [ +  + ]:      10438 :         if (strcmp(glibc_libs[i].name, name) == 0) {
     402                 :       7406 :             return &glibc_libs[i];
     403                 :            :         }
     404                 :            :     }
     405                 :          0 :     return nullptr;
     406                 :            : }

Generated by: LCOV version 1.14