Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. #include <stdarg.h>
  2. #include <stddef.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <stdint.h>
  6. #include <assert.h>
  7. #include <string.h>
  8.  
  9. #define EPEP_INST
  10. #include "epep/epep.h"
  11.  
  12. const char *epep_errors[] = {
  13.         "EPEP_ERR_SUCCESS",
  14.         "EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID",
  15.         "EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID",
  16.         "EPEP_ERR_SYMBOL_INDEX_IS_INVALID",
  17.         "EPEP_ERR_NOT_AN_OBJECT",
  18.         "EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA",
  19.         "EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO",
  20.         "EPEP_ERR_OUTPUT_IS_NULL",
  21.         "EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION",
  22.         "EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND",
  23.         "EPEP_ERR_NO_BASE_RELOCATION_TABLE",
  24.         "EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END",
  25.         "EPEP_ERR_INVALID_DATA_DIRECTORY_OFFSET",
  26.         "EPEP_ERR_INVALID_SECTION_HEADER_OFFSET",
  27.         "EPEP_ERR_INVALID_SECTION_DATA_OFFSET",
  28.         "EPEP_ERR_INVALID_STRING_TABLE_SIZE_OFFSET",
  29.         "EPEP_ERR_INVALID_SYMBOL_OFFSET",
  30.         "EPEP_ERR_INVALID_IMPORT_DIRECTORY_OFFSET",
  31.         "EPEP_ERR_INVALID_IMPORT_DIRECTORY_NAME_OFFSET",
  32.         "EPEP_ERR_INVALID_LOOKUP_OFFSET",
  33.         "EPEP_ERR_INVALID_LOOKUP_NAME_OFFSET",
  34.         "EPEP_ERR_INVALID_EXPORT_TABLE_OFFSET",
  35.         "EPEP_ERR_INVALID_DLL_NAME_OFFSET",
  36.         "EPEP_ERR_INVALID_EXPORT_NAME_POINTER_OFFSET",
  37.         "EPEP_ERR_INVALID_ORDINAL_TABLE_OFFSET",
  38.         "EPEP_ERR_INVALID_EXPORT_NAME_OFFSET",
  39.         "EPEP_ERR_INVALID_EXPORT_ADDRESS_OFFSET",
  40.         "EPEP_ERR_INVALID_FORWARDER_OFFSET",
  41.         "EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_OFFSET",
  42.         "EPEP_ERR_INVALID_NEXT_BASE_RELOCATION_BLOCK_OFFSET",
  43.         "EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_BASE_RELOCATION_OFFSET",
  44.         "EPEP_ERR_INVALID_SECTION_RELOCATION_OFFSET",
  45.         "EPEP_ERR_INVALID_LINENUMBER_OFFSET",
  46. };
  47.  
  48. #define ERROR_EPEP(epep) printf("Error: epep returned %u (%s) at "__FILE__":%u", \
  49.                                 (epep)->error_code, epep_errors[(epep)->error_code], __LINE__); exit(-1)
  50.  
  51. static int emit_logs;
  52. static void log_info(const char *fmt, ...) {
  53.         if (emit_logs) {
  54.                 va_list ap;
  55.                 va_start(ap, fmt);
  56.                 vprintf(fmt, ap);
  57.                 va_end(ap);
  58.         }
  59. }
  60.  
  61. uint32_t get32(const char *buf, size_t offset) {
  62.         return ((uint32_t)(uint8_t)buf[offset + 0] << 0)
  63.                  | ((uint32_t)(uint8_t)buf[offset + 1] << 8)
  64.                  | ((uint32_t)(uint8_t)buf[offset + 2] << 16)
  65.                  | ((uint32_t)(uint8_t)buf[offset + 3] << 24);
  66. }
  67.  
  68. EpepCoffRelocation get_relocation_for_section_and_offset(Epep *epep, EpepSectionHeader *sh, size_t offset) {
  69.         EpepCoffRelocation rel = { 0 };
  70.         for (size_t i = 0; i < sh->NumberOfRelocations; i++) {
  71.                 if (!epep_get_section_relocation_by_index(epep, sh, &rel, i)) {
  72.                         ERROR_EPEP(epep);
  73.                 }
  74.                 if (rel.VirtualAddress == offset) {
  75.                         return rel;
  76.                 }
  77.         }
  78.         printf("Error: Can't find relocation of pointer to name of symbol");
  79.         exit(-1);
  80.         return rel;
  81. }
  82.  
  83. char *read_string(Epep *epep, size_t section_index, size_t offset) {
  84.         EpepSectionHeader sh = { 0 };
  85.         if (!epep_get_section_header_by_index(epep, &sh, section_index)) {
  86.                 ERROR_EPEP(epep);
  87.         }
  88.         char *section = calloc(1, sh.SizeOfRawData);
  89.         if (!epep_get_section_contents(epep, &sh, section)) {
  90.                 ERROR_EPEP(epep);
  91.         }
  92.         char *result = strdup(&section[offset]);
  93.         free(section);
  94.         return result;
  95. }
  96.  
  97. int gendef(const char *obj_path, const char *outname) {
  98.         FILE *out = fopen(outname, "wb");
  99.         Epep epep;
  100.         {
  101.                 FILE *fp = fopen(obj_path, "rb");
  102.                 if (!fp) {
  103.                         printf("Error: Can't open \"%s\"", obj_path);
  104.                         exit(-1);
  105.                 }
  106.  
  107.                 if (!epep_init(&epep, fp)) {
  108.                         ERROR_EPEP(&epep);
  109.                 }
  110.         }
  111.  
  112.         size_t strtab_size = 0;
  113.         if (!epep_get_string_table_size(&epep, &strtab_size)) {
  114.                 ERROR_EPEP(&epep);
  115.         }
  116.  
  117.         char *strtab = malloc(strtab_size);
  118.         if (!epep_get_string_table(&epep, strtab)) {
  119.                 ERROR_EPEP(&epep);
  120.         }
  121.  
  122.         for (size_t sym_i = 0; sym_i < epep.coffFileHeader.NumberOfSymbols; sym_i++) {
  123.                 EpepCoffSymbol sym = { 0 };
  124.  
  125.                 if (!epep_get_symbol_by_index(&epep, &sym, sym_i)) {
  126.                         ERROR_EPEP(&epep);
  127.                 }
  128.  
  129.                 size_t name_max = 1024;
  130.                 char name[name_max];
  131.  
  132.                 if (sym.symbol.Zeroes == 0) {
  133.                         strcpy(name, &strtab[sym.symbol.Offset]);
  134.                 } else {
  135.                         memcpy(name, sym.symbol.ShortName, 8);
  136.                         name[8] = '\0';
  137.                 }
  138.  
  139.                 if (!strcmp(name, "_EXPORTS") || !strcmp(name, "EXPORTS")) {
  140.                         fprintf(out, "LIBRARY %s\n\nEXPORTS\n", obj_path);
  141.  
  142.                         size_t export_table_offset_in_section = sym.symbol.Value;
  143.                         size_t section_index = sym.symbol.SectionNumber - 1;
  144.                         EpepSectionHeader sh = { 0 };
  145.                         if (!epep_get_section_header_by_index(&epep, &sh, section_index)) {
  146.                                 ERROR_EPEP(&epep);
  147.                         }
  148.                         size_t section_offset = sh.PointerToRawData;
  149.                         size_t export_table_offset = section_offset + export_table_offset_in_section;
  150.  
  151.                         char *section = calloc(1, sh.SizeOfRawData);
  152.                         if (!epep_get_section_contents(&epep, &sh, section)) {
  153.                                 ERROR_EPEP(&epep);
  154.                         }
  155.  
  156.                         for (size_t offset = export_table_offset_in_section;; offset += 8) {
  157.                                 size_t name_offset = get32(section, offset);
  158.                                 size_t data_offset = get32(section, offset + 4);
  159.  
  160.                                 if (name_offset == 0 || data_offset == 0) {
  161.                                         break;
  162.                                 }
  163.  
  164.                                 EpepCoffRelocation rel = get_relocation_for_section_and_offset(&epep, &sh, offset);
  165.                                 EpepCoffSymbol name_sym = { 0 };
  166.                                 if (!epep_get_symbol_by_index(&epep, &name_sym, rel.SymbolTableIndex)) {
  167.                                         ERROR_EPEP(&epep);
  168.                                 }
  169.                                 size_t name_offset_in_section = name_sym.symbol.Value + name_offset;
  170.                                 char *name = read_string(&epep, name_sym.symbol.SectionNumber - 1, name_offset_in_section);
  171.                                 fprintf(out, "%s\n", name);
  172.                         }
  173.                         break;
  174.                 }
  175.                 sym_i += sym.symbol.NumberOfAuxSymbols;
  176.         }
  177. }
  178.  
  179. int arg_got_flag(int argc, char **argv, ...) {
  180.         char *arg_names[8];
  181.         int arg_name_c = 0;
  182.  
  183.         va_list ap;
  184.         va_start(ap, argv);
  185.         for (char *arg_name = va_arg(ap, char *); arg_name; arg_name = va_arg(ap, char *)) {
  186.                 if (arg_name_c >= 8) {
  187.                         printf("Internal error: Too many parameter aliases passed to %s", __func__);
  188.                         exit(-1);
  189.                 }
  190.                 arg_names[arg_name_c++] = arg_name;
  191.         }
  192.         va_end(ap);
  193.  
  194.         for (int i = 1; i < argc; i++) {
  195.                 // If an argumetns was handled already then it's NULL here
  196.                 if (argv[i] == NULL) {
  197.                         continue;
  198.                 }
  199.                 for (int arg_name_i = 0; arg_name_i < arg_name_c; arg_name_i++) {
  200.                         char *arg_name = arg_names[arg_name_i];
  201.                         if (!strcmp(argv[i], arg_name)) {
  202.                                 argv[i] = NULL; // Do not handle this argument as a input name
  203.                                 return i;
  204.                         }
  205.                 }
  206.         }
  207.         return 0;
  208. }
  209.  
  210. char *arg_got_param(int argc, char **argv, char *arg) {
  211.         int i = arg_got_flag(argc, argv, arg, 0);
  212.         if (i == 0) {
  213.                 return NULL;
  214.         }
  215.  
  216.         if (i + 1 >= argc) {
  217.                 printf("Warning: %s parameter expects a value (like %s <value>)", arg, arg);
  218.                 return NULL;
  219.         }
  220.         char *result = argv[i + 1];
  221.         argv[i + 1] = NULL;
  222.         return result;
  223. }
  224.  
  225. int usage(char *name, char *remark) {
  226.         if (remark) {
  227.                 printf("Error: %s\n\n", remark);
  228.         }
  229.         printf("Usage: %s [option]... [object file name]...\n", name);
  230.         printf("  Generate DEF files from COFF objects\n");
  231.         printf("\n");
  232.         printf("Options:\n");
  233.         printf("  -v, --verbose Emit information logs\n");
  234.         printf("  -h, --help    Output this help and exit\n");
  235.         return 0;
  236. }
  237.  
  238. int main(int argc, char **argv) {
  239.         if (arg_got_flag(argc, argv, "-h", "-help", "--help", 0)) {
  240.                 return usage(argv[0], NULL);
  241.         }
  242.  
  243.         emit_logs = arg_got_flag(argc, argv, "-v", "-verbose", "--verbose", 0);
  244.  
  245.         // After handling arguments there only leaven unhandled ones
  246.         // They should be names if inputs. But if there's no input - exit
  247.         int input_file_count = 0;
  248.         for (int i = 1; i < argc; i++) {
  249.                 if (argv[i] != NULL) {
  250.                         input_file_count++;
  251.                 }
  252.         }
  253.         if (input_file_count == 0) {
  254.                 return usage(argv[0], "No input file names supplied");
  255.         }
  256.  
  257.         for (size_t i = 1; i < argc; i++) {
  258.                 char outname[256] = { 0 };
  259.                 sprintf(outname, "%.*s.def", strlen(argv[i]) - strlen(".obj"), argv[i]);
  260.                 if (argv[i] != NULL) {
  261.                         gendef(argv[i], outname);
  262.                 }
  263.         }
  264.         return 0;
  265. }
  266.