"Fossies" - the Fresh Open Source Software Archive

Member "dmd2/src/dmd/dmd/libelf.d" (20 Nov 2020, 18789 Bytes) of package /linux/misc/dmd.2.094.2.linux.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) D source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /**
    2  * A library in the ELF format, used on Unix.
    3  *
    4  * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
    5  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
    6  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
    7  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/libelf.d, _libelf.d)
    8  * Documentation:  https://dlang.org/phobos/dmd_libelf.html
    9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/libelf.d
   10  */
   11 
   12 module dmd.libelf;
   13 
   14 version(Windows) {}
   15 else version(OSX) {}
   16 else:
   17 
   18 import core.stdc.time;
   19 import core.stdc.string;
   20 import core.stdc.stdlib;
   21 import core.stdc.stdio;
   22 import core.sys.posix.sys.stat;
   23 import core.sys.posix.unistd;
   24 
   25 import dmd.globals;
   26 import dmd.lib;
   27 import dmd.utils;
   28 
   29 import dmd.root.array;
   30 import dmd.root.file;
   31 import dmd.root.filename;
   32 import dmd.root.outbuffer;
   33 import dmd.root.port;
   34 import dmd.root.rmem;
   35 import dmd.root.string;
   36 import dmd.root.stringtable;
   37 
   38 import dmd.scanelf;
   39 
   40 // Entry point (only public symbol in this module).
   41 public extern (C++) Library LibElf_factory()
   42 {
   43     return new LibElf();
   44 }
   45 
   46 private: // for the remainder of this module
   47 
   48 enum LOG = false;
   49 
   50 struct ElfObjSymbol
   51 {
   52     const(char)[] name;
   53     ElfObjModule* om;
   54 }
   55 
   56 alias ElfObjModules = Array!(ElfObjModule*);
   57 alias ElfObjSymbols = Array!(ElfObjSymbol*);
   58 
   59 final class LibElf : Library
   60 {
   61     ElfObjModules objmodules; // ElfObjModule[]
   62     ElfObjSymbols objsymbols; // ElfObjSymbol[]
   63     StringTable!(ElfObjSymbol*) tab;
   64 
   65     extern (D) this()
   66     {
   67         tab._init(14_000);
   68     }
   69 
   70     /***************************************
   71      * Add object module or library to the library.
   72      * Examine the buffer to see which it is.
   73      * If the buffer is NULL, use module_name as the file name
   74      * and load the file.
   75      */
   76     override void addObject(const(char)[] module_name, const ubyte[] buffer)
   77     {
   78         static if (LOG)
   79         {
   80             printf("LibElf::addObject(%.*s)\n",
   81                    cast(int)module_name.length, module_name.ptr);
   82         }
   83 
   84         void corrupt(int reason)
   85         {
   86             error("corrupt ELF object module %.*s %d",
   87                   cast(int)module_name.length, module_name.ptr, reason);
   88         }
   89 
   90         int fromfile = 0;
   91         auto buf = buffer.ptr;
   92         auto buflen = buffer.length;
   93         if (!buf)
   94         {
   95             assert(module_name.length);
   96             // read file and take buffer ownership
   97             auto data = readFile(Loc.initial, module_name).extractSlice();
   98             buf = data.ptr;
   99             buflen = data.length;
  100             fromfile = 1;
  101         }
  102         if (buflen < 16)
  103         {
  104             static if (LOG)
  105             {
  106                 printf("buf = %p, buflen = %d\n", buf, buflen);
  107             }
  108             return corrupt(__LINE__);
  109         }
  110         if (memcmp(buf, "!<arch>\n".ptr, 8) == 0)
  111         {
  112             /* Library file.
  113              * Pull each object module out of the library and add it
  114              * to the object module array.
  115              */
  116             static if (LOG)
  117             {
  118                 printf("archive, buf = %p, buflen = %d\n", buf, buflen);
  119             }
  120             uint offset = 8;
  121             char* symtab = null;
  122             uint symtab_size = 0;
  123             char* filenametab = null;
  124             uint filenametab_size = 0;
  125             uint mstart = cast(uint)objmodules.dim;
  126             while (offset < buflen)
  127             {
  128                 if (offset + ElfLibHeader.sizeof >= buflen)
  129                     return corrupt(__LINE__);
  130                 ElfLibHeader* header = cast(ElfLibHeader*)(cast(ubyte*)buf + offset);
  131                 offset += ElfLibHeader.sizeof;
  132                 char* endptr = null;
  133                 uint size = cast(uint)strtoul(header.file_size.ptr, &endptr, 10);
  134                 if (endptr >= header.file_size.ptr + 10 || *endptr != ' ')
  135                     return corrupt(__LINE__);
  136                 if (offset + size > buflen)
  137                     return corrupt(__LINE__);
  138                 if (header.object_name[0] == '/' && header.object_name[1] == ' ')
  139                 {
  140                     /* Instead of rescanning the object modules we pull from a
  141                      * library, just use the already created symbol table.
  142                      */
  143                     if (symtab)
  144                         return corrupt(__LINE__);
  145                     symtab = cast(char*)buf + offset;
  146                     symtab_size = size;
  147                     if (size < 4)
  148                         return corrupt(__LINE__);
  149                 }
  150                 else if (header.object_name[0] == '/' && header.object_name[1] == '/')
  151                 {
  152                     /* This is the file name table, save it for later.
  153                      */
  154                     if (filenametab)
  155                         return corrupt(__LINE__);
  156                     filenametab = cast(char*)buf + offset;
  157                     filenametab_size = size;
  158                 }
  159                 else
  160                 {
  161                     auto om = new ElfObjModule();
  162                     om.base = cast(ubyte*)buf + offset; /*- sizeof(ElfLibHeader)*/
  163                     om.length = size;
  164                     om.offset = 0;
  165                     if (header.object_name[0] == '/')
  166                     {
  167                         /* Pick long name out of file name table
  168                          */
  169                         uint foff = cast(uint)strtoul(header.object_name.ptr + 1, &endptr, 10);
  170                         uint i;
  171                         for (i = 0; 1; i++)
  172                         {
  173                             if (foff + i >= filenametab_size)
  174                                 return corrupt(__LINE__);
  175                             char c = filenametab[foff + i];
  176                             if (c == '/')
  177                                 break;
  178                         }
  179                         auto n = cast(char*)Mem.check(malloc(i + 1));
  180                         memcpy(n, filenametab + foff, i);
  181                         n[i] = 0;
  182                         om.name = n[0 .. i];
  183                     }
  184                     else
  185                     {
  186                         /* Pick short name out of header
  187                          */
  188                         auto n = cast(char*)Mem.check(malloc(ELF_OBJECT_NAME_SIZE));
  189                         for (int i = 0; 1; i++)
  190                         {
  191                             if (i == ELF_OBJECT_NAME_SIZE)
  192                                 return corrupt(__LINE__);
  193                             char c = header.object_name[i];
  194                             if (c == '/')
  195                             {
  196                                 n[i] = 0;
  197                                 om.name = n[0 .. i];
  198                                 break;
  199                             }
  200                             n[i] = c;
  201                         }
  202                     }
  203                     om.name_offset = -1;
  204                     om.file_time = strtoul(header.file_time.ptr, &endptr, 10);
  205                     om.user_id = cast(uint)strtoul(header.user_id.ptr, &endptr, 10);
  206                     om.group_id = cast(uint)strtoul(header.group_id.ptr, &endptr, 10);
  207                     om.file_mode = cast(uint)strtoul(header.file_mode.ptr, &endptr, 8);
  208                     om.scan = 0; // don't scan object module for symbols
  209                     objmodules.push(om);
  210                 }
  211                 offset += (size + 1) & ~1;
  212             }
  213             if (offset != buflen)
  214                 return corrupt(__LINE__);
  215             /* Scan the library's symbol table, and insert it into our own.
  216              * We use this instead of rescanning the object module, because
  217              * the library's creator may have a different idea of what symbols
  218              * go into the symbol table than we do.
  219              * This is also probably faster.
  220              */
  221             uint nsymbols = Port.readlongBE(symtab);
  222             char* s = symtab + 4 + nsymbols * 4;
  223             if (4 + nsymbols * (4 + 1) > symtab_size)
  224                 return corrupt(__LINE__);
  225             for (uint i = 0; i < nsymbols; i++)
  226             {
  227                 const(char)[] name = s.toDString();
  228                 s += name.length + 1;
  229                 if (s - symtab > symtab_size)
  230                     return corrupt(__LINE__);
  231                 uint moff = Port.readlongBE(symtab + 4 + i * 4);
  232                 //printf("symtab[%d] moff = %x  %x, name = %s\n", i, moff, moff + sizeof(Header), name.ptr);
  233                 for (uint m = mstart; 1; m++)
  234                 {
  235                     if (m == objmodules.dim)
  236                         return corrupt(__LINE__);  // didn't find it
  237                     ElfObjModule* om = objmodules[m];
  238                     //printf("\t%x\n", (char *)om.base - (char *)buf);
  239                     if (moff + ElfLibHeader.sizeof == cast(char*)om.base - cast(char*)buf)
  240                     {
  241                         addSymbol(om, name, 1);
  242                         //if (mstart == m)
  243                         //    mstart++;
  244                         break;
  245                     }
  246                 }
  247             }
  248             return;
  249         }
  250         /* It's an object module
  251          */
  252         auto om = new ElfObjModule();
  253         om.base = cast(ubyte*)buf;
  254         om.length = cast(uint)buflen;
  255         om.offset = 0;
  256         // remove path, but not extension
  257         om.name = FileName.name(module_name);
  258         om.name_offset = -1;
  259         om.scan = 1;
  260         if (fromfile)
  261         {
  262             stat_t statbuf;
  263             int i = module_name.toCStringThen!(slice => stat(slice.ptr, &statbuf));
  264             if (i == -1) // error, errno is set
  265                 return corrupt(__LINE__);
  266             om.file_time = statbuf.st_ctime;
  267             om.user_id = statbuf.st_uid;
  268             om.group_id = statbuf.st_gid;
  269             om.file_mode = statbuf.st_mode;
  270         }
  271         else
  272         {
  273             /* Mock things up for the object module file that never was
  274              * actually written out.
  275              */
  276             __gshared uid_t uid;
  277             __gshared gid_t gid;
  278             __gshared int _init;
  279             if (!_init)
  280             {
  281                 _init = 1;
  282                 uid = getuid();
  283                 gid = getgid();
  284             }
  285             time(&om.file_time);
  286             om.user_id = uid;
  287             om.group_id = gid;
  288             om.file_mode = (1 << 15) | (6 << 6) | (4 << 3); // 0100640
  289         }
  290         objmodules.push(om);
  291     }
  292 
  293     /*****************************************************************************/
  294 
  295     void addSymbol(ElfObjModule* om, const(char)[] name, int pickAny = 0)
  296     {
  297         static if (LOG)
  298         {
  299             printf("LibElf::addSymbol(%s, %s, %d)\n", om.name.ptr, name.ptr, pickAny);
  300         }
  301         auto s = tab.insert(name.ptr, name.length, null);
  302         if (!s)
  303         {
  304             // already in table
  305             if (!pickAny)
  306             {
  307                 s = tab.lookup(name.ptr, name.length);
  308                 assert(s);
  309                 ElfObjSymbol* os = s.value;
  310                 error("multiple definition of %s: %s and %s: %s", om.name.ptr, name.ptr, os.om.name.ptr, os.name.ptr);
  311             }
  312         }
  313         else
  314         {
  315             auto os = new ElfObjSymbol();
  316             os.name = xarraydup(name);
  317             os.om = om;
  318             s.value = os;
  319             objsymbols.push(os);
  320         }
  321     }
  322 
  323 private:
  324     /************************************
  325      * Scan single object module for dictionary symbols.
  326      * Send those symbols to LibElf::addSymbol().
  327      */
  328     void scanObjModule(ElfObjModule* om)
  329     {
  330         static if (LOG)
  331         {
  332             printf("LibElf::scanObjModule(%s)\n", om.name.ptr);
  333         }
  334 
  335         extern (D) void addSymbol(const(char)[] name, int pickAny)
  336         {
  337             this.addSymbol(om, name, pickAny);
  338         }
  339 
  340         scanElfObjModule(&addSymbol, om.base[0 .. om.length], om.name.ptr, loc);
  341     }
  342 
  343     /*****************************************************************************/
  344     /*****************************************************************************/
  345     /**********************************************
  346      * Create and write library to libbuf.
  347      * The library consists of:
  348      *      !<arch>\n
  349      *      header
  350      *      dictionary
  351      *      object modules...
  352      */
  353     protected override void WriteLibToBuffer(OutBuffer* libbuf)
  354     {
  355         static if (LOG)
  356         {
  357             printf("LibElf::WriteLibToBuffer()\n");
  358         }
  359         /************* Scan Object Modules for Symbols ******************/
  360         foreach (om; objmodules)
  361         {
  362             if (om.scan)
  363             {
  364                 scanObjModule(om);
  365             }
  366         }
  367         /************* Determine string section ******************/
  368         /* The string section is where we store long file names.
  369          */
  370         uint noffset = 0;
  371         foreach (om; objmodules)
  372         {
  373             size_t len = om.name.length;
  374             if (len >= ELF_OBJECT_NAME_SIZE)
  375             {
  376                 om.name_offset = noffset;
  377                 noffset += len + 2;
  378             }
  379             else
  380                 om.name_offset = -1;
  381         }
  382         static if (LOG)
  383         {
  384             printf("\tnoffset = x%x\n", noffset);
  385         }
  386         /************* Determine module offsets ******************/
  387         uint moffset = 8 + ElfLibHeader.sizeof + 4;
  388         foreach (os; objsymbols)
  389         {
  390             moffset += 4 + os.name.length + 1;
  391         }
  392         uint hoffset = moffset;
  393         static if (LOG)
  394         {
  395             printf("\tmoffset = x%x\n", moffset);
  396         }
  397         moffset += moffset & 1;
  398         if (noffset)
  399             moffset += ElfLibHeader.sizeof + noffset;
  400         foreach (om; objmodules)
  401         {
  402             moffset += moffset & 1;
  403             om.offset = moffset;
  404             moffset += ElfLibHeader.sizeof + om.length;
  405         }
  406         libbuf.reserve(moffset);
  407         /************* Write the library ******************/
  408         libbuf.write("!<arch>\n");
  409         ElfObjModule om;
  410         om.name_offset = -1;
  411         om.base = null;
  412         om.length = cast(uint)(hoffset - (8 + ElfLibHeader.sizeof));
  413         om.offset = 8;
  414         om.name = "";
  415         .time(&om.file_time);
  416         om.user_id = 0;
  417         om.group_id = 0;
  418         om.file_mode = 0;
  419         ElfLibHeader h;
  420         ElfOmToHeader(&h, &om);
  421         libbuf.write((&h)[0 .. 1]);
  422         char[4] buf;
  423         Port.writelongBE(cast(uint)objsymbols.dim, buf.ptr);
  424         libbuf.write(buf[0 .. 4]);
  425         foreach (os; objsymbols)
  426         {
  427             Port.writelongBE(os.om.offset, buf.ptr);
  428             libbuf.write(buf[0 .. 4]);
  429         }
  430         foreach (os; objsymbols)
  431         {
  432             libbuf.writestring(os.name);
  433             libbuf.writeByte(0);
  434         }
  435         static if (LOG)
  436         {
  437             printf("\tlibbuf.moffset = x%x\n", libbuf.length);
  438         }
  439         /* Write out the string section
  440          */
  441         if (noffset)
  442         {
  443             if (libbuf.length & 1)
  444                 libbuf.writeByte('\n');
  445             // header
  446             memset(&h, ' ', ElfLibHeader.sizeof);
  447             h.object_name[0] = '/';
  448             h.object_name[1] = '/';
  449             size_t len = sprintf(h.file_size.ptr, "%u", noffset);
  450             assert(len < 10);
  451             h.file_size[len] = ' ';
  452             h.trailer[0] = '`';
  453             h.trailer[1] = '\n';
  454             libbuf.write((&h)[0 .. 1]);
  455             foreach (om2; objmodules)
  456             {
  457                 if (om2.name_offset >= 0)
  458                 {
  459                     libbuf.writestring(om2.name);
  460                     libbuf.writeByte('/');
  461                     libbuf.writeByte('\n');
  462                 }
  463             }
  464         }
  465         /* Write out each of the object modules
  466          */
  467         foreach (om2; objmodules)
  468         {
  469             if (libbuf.length & 1)
  470                 libbuf.writeByte('\n'); // module alignment
  471             assert(libbuf.length == om2.offset);
  472             ElfOmToHeader(&h, om2);
  473             libbuf.write((&h)[0 .. 1]); // module header
  474             libbuf.write(om2.base[0 .. om2.length]); // module contents
  475         }
  476         static if (LOG)
  477         {
  478             printf("moffset = x%x, libbuf.length = x%x\n", moffset, libbuf.length);
  479         }
  480         assert(libbuf.length == moffset);
  481     }
  482 }
  483 
  484 /*****************************************************************************/
  485 /*****************************************************************************/
  486 struct ElfObjModule
  487 {
  488     ubyte* base; // where are we holding it in memory
  489     uint length; // in bytes
  490     uint offset; // offset from start of library
  491     const(char)[] name; // module name (file name) with terminating 0
  492     int name_offset; // if not -1, offset into string table of name
  493     time_t file_time; // file time
  494     uint user_id;
  495     uint group_id;
  496     uint file_mode;
  497     int scan; // 1 means scan for symbols
  498 }
  499 
  500 enum ELF_OBJECT_NAME_SIZE = 16;
  501 
  502 struct ElfLibHeader
  503 {
  504     char[ELF_OBJECT_NAME_SIZE] object_name;
  505     char[12] file_time;
  506     char[6] user_id;
  507     char[6] group_id;
  508     char[8] file_mode; // in octal
  509     char[10] file_size;
  510     char[2] trailer;
  511 }
  512 
  513 extern (C++) void ElfOmToHeader(ElfLibHeader* h, ElfObjModule* om)
  514 {
  515     char* buffer = cast(char*)h;
  516     // user_id and group_id are padded on 6 characters in Header struct.
  517     // Squashing to 0 if more than 999999.
  518     if (om.user_id > 999_999)
  519         om.user_id = 0;
  520     if (om.group_id > 999_999)
  521         om.group_id = 0;
  522     size_t len;
  523     if (om.name_offset == -1)
  524     {
  525         // "name/           1423563789  5000  5000  100640  3068      `\n"
  526         //  |^^^^^^^^^^^^^^^|^^^^^^^^^^^|^^^^^|^^^^^|^^^^^^^|^^^^^^^^^|^^
  527         //        name       file_time   u_id gr_id  fmode    fsize   trailer
  528         len = snprintf(buffer, ElfLibHeader.sizeof, "%-16s%-12llu%-6u%-6u%-8o%-10u`", om.name.ptr, cast(long)om.file_time, om.user_id, om.group_id, om.file_mode, om.length);
  529         // adding '/' after the name field
  530         const(size_t) name_length = om.name.length;
  531         assert(name_length < ELF_OBJECT_NAME_SIZE);
  532         buffer[name_length] = '/';
  533     }
  534     else
  535     {
  536         // "/162007         1423563789  5000  5000  100640  3068      `\n"
  537         //  |^^^^^^^^^^^^^^^|^^^^^^^^^^^|^^^^^|^^^^^|^^^^^^^|^^^^^^^^^|^^
  538         //     name_offset   file_time   u_id gr_id  fmode    fsize   trailer
  539         len = snprintf(buffer, ElfLibHeader.sizeof, "/%-15d%-12llu%-6u%-6u%-8o%-10u`", om.name_offset, cast(long)om.file_time, om.user_id, om.group_id, om.file_mode, om.length);
  540     }
  541     assert(ElfLibHeader.sizeof > 0 && len == ElfLibHeader.sizeof - 1);
  542     // replace trailing \0 with \n
  543     buffer[len] = '\n';
  544 }