Significant progress to getting pl1$pl1 to compile something, implemented many necess...
[multics_sim.git] / dump_segments.c
1 #include <fcntl.h>
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/mman.h>
8 #include <sys/stat.h>
9 #include <unistd.h>
10 #include "definition_dcls.h"
11 #include "object_map.h"
12 #include "rassert.h"
13
14 uint64_t *load_segment(const char *path, int *bitcount) {
15   int fd = open(path, O_RDONLY);
16   if (fd == -1) {
17     fprintf(stderr, "can't find segment at %s\n", path);
18     exit(EXIT_FAILURE);
19   }
20
21   uint64_t *segment = (uint64_t *)mmap(
22     NULL,
23     01000000 * sizeof(uint64_t),
24     PROT_READ,
25     MAP_SHARED,
26     fd,
27     (off_t)0
28   );
29   rassert(segment != (uint64_t *)-1);
30
31   struct stat stat_buf;
32   rassert(fstat(fd, &stat_buf) != -1);
33
34   close(fd);
35
36   int i = strlen(path);
37   for (; i && path[i - 1] != '/'; --i)
38     ;
39   const char *name = path + i;
40
41   char path_dir[0x1000];
42   rassert(i + 4 < sizeof(path_dir));
43   memcpy(path_dir, path, i);
44   strcpy(path_dir + i, ".dir");
45
46   FILE *fp = fopen(path_dir, "r");
47   if (fp == NULL) {
48     fprintf(stderr, "can't find index %s\n", path_dir);
49     exit(EXIT_FAILURE);
50   }
51   char line[0x100];
52   while (fgets(line, 0x100, fp)) {
53     char *p = strchr(line, ' ');
54     if (p) {
55       *p++ = 0;
56       if (strcmp(line, name) == 0) {
57         fclose(fp);
58         *bitcount = (int)strtol(p, NULL, 0);
59         goto found_bitcount;
60       }
61     }
62   }
63   fclose(fp);
64
65   fprintf(stderr, "can't find segment name %s in index %s\n", name, path_dir);
66   exit(EXIT_FAILURE);
67
68 found_bitcount:
69   if (*bitcount > (stat_buf.st_size / sizeof(uint64_t)) * 36) {
70     fprintf(
71       stderr,
72       "file size %ld bytes too short for bitcount %d\n",
73       stat_buf.st_size,
74       *bitcount
75     );
76     exit(EXIT_FAILURE);
77   }
78
79   return segment;
80 }
81
82 struct object_map *get_object_map(uint64_t *segment, int bitcount) {
83   if (bitcount % 36 != 0) {
84     fprintf(stderr, "bitcount %d not multiple of 36\n", bitcount);
85     exit(EXIT_FAILURE);
86   }
87
88   int wordcount = (bitcount / 36) & 0777777;
89   if (wordcount < 1) {
90     fprintf(stderr, "wordcount %d too short\n", wordcount);
91     exit(EXIT_FAILURE);
92   }
93
94   int object_map_offset = (segment[wordcount - 1] >> 18) & 0777777;
95   if (
96     object_map_offset + sizeof(struct object_map) / sizeof(uint64_t) + 1 >
97       wordcount
98   ) {
99     printf("bad object map offset\n");
100     exit(EXIT_FAILURE);
101   }
102
103   struct object_map *object_map = (struct object_map *)(
104     segment + object_map_offset
105   );
106   if (
107     object_map->decl_vers != 2 ||
108     object_map->identifier[0] != 0157142152137 || // 'obj_'
109     object_map->identifier[1] != 0155141160040 // 'map '
110   ) {
111     fprintf(stderr, "bad object map signature\n");
112     exit(EXIT_FAILURE);
113   }
114
115   return object_map;
116 }
117
118 void get_acc_string(uint64_t *acc_string, char *buf, int buf_len) {
119   int len = (acc_string[0] >> 27) & 0777;
120   rassert(len < buf_len);
121
122   static int shifts[4] = {27, 18, 9, 0};
123   for (int i = 0, j = 1; i < len; ++i, ++j)
124     buf[i] = (char)(acc_string[j >> 2] >> shifts[j & 3]);
125   buf[len] = 0;
126 }
127
128 void dump_segments(uint64_t *segment, int bitcount) {
129   struct object_map *object_map = get_object_map(segment, bitcount);
130   struct definition_header *definition_header = (struct definition_header *)(
131     segment + object_map->definition_offset
132   );
133
134   for (
135     struct segname_definition *segname_definition =
136       (struct segname_definition *)(
137         (uint64_t *)definition_header + definition_header->def_list_relp
138       );
139     *(uint64_t *)segname_definition;
140     segname_definition = (struct segname_definition *)(
141       (uint64_t *)definition_header + segname_definition->next_segname_relp
142     )
143   ) {
144     rassert(segname_definition->class == CLASS_SEGNAME);
145
146     char name[0x100];
147     get_acc_string(
148       (uint64_t *)definition_header + segname_definition->name_relp,
149       name,
150       sizeof(name)
151     );
152     printf("%s\n", name);
153   }
154 }
155
156 int main(int argc, char **argv) {
157   if (argc < 2) {
158     printf(
159       "usage: %s path_to_segment\n",
160       argv[0]
161     );
162     exit(EXIT_FAILURE);
163   }
164
165   int bitcount;
166   uint64_t *segment = load_segment(argv[1], &bitcount);
167   dump_segments(segment, bitcount);
168
169   return 0;
170 }