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