PageRenderTime 267ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/CSC586A/A2/ReadClassFile.c

https://github.com/jordanell/School
C | 353 lines | 297 code | 36 blank | 20 comment | 44 complexity | f0e535f7454c725c9bb081b8dd7f3140 MD5 | raw file
  1. /* ReadClassFile.c */
  2. /*
  3. Reads a class from a file, building a representation in memory as an
  4. instance of the ClassFile struct.
  5. Attributes other than those explicitly needed by the MyJVM program
  6. are ignored.
  7. */
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <stdarg.h>
  11. #include <string.h>
  12. #include <assert.h>
  13. #include <stdint.h>
  14. #include "ClassFileFormat.h"
  15. #include "ReadClassFile.h"
  16. #include "MyAlloc.h"
  17. typedef struct FileNameListItem {
  18. char *filename;
  19. int cnt; // number of tries
  20. struct FileNameListItem *next;
  21. } *FileNameList;
  22. static FileNameList filesRead = NULL; // list of class files we tried to read
  23. void PrintFilesRead() {
  24. if (filesRead == NULL) {
  25. printf("\nNo class files read\n");
  26. return;
  27. }
  28. FileNameList fnp;
  29. printf("\nRequests to Read Class Files...\n");
  30. for( fnp = filesRead; fnp != NULL; fnp = fnp->next ) {
  31. printf(" (%d times): %s\n", fnp->cnt, fnp->filename);
  32. }
  33. }
  34. static uint32_t ReadU4(FILE *f) {
  35. uint32_t r = 0;
  36. r = fgetc(f) & 0xff;
  37. r = (r << 8) | (fgetc(f) & 0xff);
  38. r = (r << 8) | (fgetc(f) & 0xff);
  39. r = (r << 8) | (fgetc(f) & 0xff);
  40. return r;
  41. }
  42. static uint16_t ReadU2(FILE *f) {
  43. uint16_t r = 0;
  44. r = fgetc(f) & 0xff;
  45. r = (r << 8) | (fgetc(f) & 0xff);
  46. return r;
  47. }
  48. static void ReadConstantPool(FILE *f, ClassFile *cf) {\
  49. uint16_t cnt;
  50. int i;
  51. ConstantPoolTag t;
  52. uint8_t *s;
  53. int len;
  54. cf->constant_pool_count = cnt = ReadU2(f);
  55. cf->cp_tag = SafeCalloc(cnt,sizeof(uint8_t));
  56. cf->cp_item = SafeCalloc(cnt,sizeof(ConstantPoolItem));
  57. for( i=1; i<cnt; i++ ) {
  58. t = (ConstantPoolTag)fgetc(f);
  59. cf->cp_tag[i] = (uint8_t)t;
  60. switch(t) {
  61. case CP_UTF8:
  62. len = ReadU2(f);
  63. // We allocate an extra null byte at end of the string.
  64. // This allows most UTF8 strings to be treated as regular
  65. // ASCII strings in C.
  66. cf->cp_item[i].sval = s = SafeMalloc(len+3);
  67. *s++ = (len >> 8);
  68. *s++ = len & 0xff;
  69. while(len-- > 0)
  70. *s++ = fgetc(f);
  71. *s = 0;
  72. break;
  73. case CP_Integer:
  74. case CP_Float:
  75. cf->cp_item[i].ival = ReadU4(f);
  76. break;
  77. case CP_Long:
  78. case CP_Double:
  79. cf->cp_item[i+1].ival = ReadU4(f);
  80. cf->cp_item[i].ival = ReadU4(f);
  81. cf->cp_tag[++i] = (uint8_t)t;
  82. break;
  83. case CP_Class:
  84. case CP_String:
  85. cf->cp_item[i].ival = ReadU2(f);
  86. break;
  87. case CP_Field:
  88. case CP_Method:
  89. case CP_Interface:
  90. case CP_NameAndType:
  91. cf->cp_item[i].ss.sval1 = ReadU2(f);
  92. cf->cp_item[i].ss.sval2 = ReadU2(f);
  93. break;
  94. default:
  95. cf->cp_tag[i] = CP_Unknown;
  96. cf->cp_item[i].ival = 0;
  97. break;
  98. }
  99. }
  100. }
  101. static void ReadInterfaces(FILE *f, ClassFile *cf) {
  102. int cnt;
  103. uint16_t *ip;
  104. cf->interfaces_count = cnt = ReadU2(f);
  105. cf->interfaces = ip = SafeCalloc(cnt,2);
  106. while(cnt-- > 0)
  107. *ip++ = ReadU2(f);
  108. }
  109. // Reads up to 3 different attributes
  110. static void ReadAttributes(FILE *f, ClassFile *cf, ... ) {
  111. int acnt;
  112. va_list argp;
  113. char *name[3];
  114. uint32_t *length[3];
  115. uint8_t **where[3];
  116. int num = 0;
  117. acnt = ReadU2(f);
  118. if (acnt == 0) {
  119. return;
  120. }
  121. va_start(argp, cf);
  122. for( ; ; ) {
  123. assert(num < 3);
  124. name[num] = va_arg(argp, char*);
  125. if (name[num] == NULL) break;
  126. length[num] = va_arg(argp, uint32_t*);
  127. where[num] = va_arg(argp, uint8_t**);
  128. *where[num] = NULL;
  129. num++;
  130. }
  131. va_end(argp);
  132. while(acnt-- > 0) {
  133. uint16_t ix = ReadU2(f);
  134. uint8_t *ap = NULL;
  135. int len = ReadU4(f);
  136. int i;
  137. for( i=0; i<num; i++ ) {
  138. // look up the attribute name in the constant pool
  139. char *s = GetUTF8(cf,ix);
  140. if (strcmp(s,name[i]) == 0) {
  141. /* this is an attribute we want */
  142. *length[i] = len;
  143. *where[i] = ap = SafeMalloc(len);
  144. fread(ap, 1, len, f);
  145. break;
  146. }
  147. }
  148. if (ap == NULL && len > 0)
  149. /* it's an attribute we ignore */
  150. fseek(f,len,SEEK_CUR);
  151. }
  152. }
  153. static void ReadFields(FILE *f, ClassFile *cf) {
  154. int cnt;
  155. field_info *ip;
  156. uint32_t attr_len;
  157. uint8_t *attr;
  158. cf->fields_count = cnt = ReadU2(f);
  159. cf->fields = ip = SafeCalloc(cnt, sizeof(field_info));
  160. while(cnt-- > 0) {
  161. ip->access_flags = ReadU2(f);
  162. ip->name_index = ReadU2(f);
  163. ip->descriptor_index = ReadU2(f);
  164. ip->constantValue_index = 0;
  165. attr = (uint8_t*)(&ip->constantValue_index);
  166. ReadAttributes(f, cf, "ConstantValue", &attr_len, &attr, NULL);
  167. ip++;
  168. }
  169. }
  170. int CountParameters( uint8_t *s ) {
  171. int result = 0;
  172. assert(*s == '(');
  173. s++;
  174. while(*s != '\0') {
  175. switch(*s++) {
  176. case 'B':
  177. case 'C':
  178. case 'F':
  179. case 'I':
  180. case 'S':
  181. case 'Z':
  182. result++;
  183. break;
  184. case 'D':
  185. case 'J':
  186. result += 2; // these types take 2 slots
  187. break;
  188. case 'L':
  189. result++;
  190. while(*s++ != ';')
  191. ;
  192. break;
  193. case '[':
  194. while(*s == '[')
  195. s++;
  196. if (*s == 'L') {
  197. while(*s++ != ';')
  198. ;
  199. } else if (*s != '\0')
  200. s++;
  201. result++;
  202. break;
  203. case ')':
  204. return result;
  205. }
  206. }
  207. /* should not be reached */
  208. assert(*s == ')');
  209. return result;
  210. }
  211. static void ReadMethods(FILE *f, ClassFile *cf) {
  212. int cnt;
  213. method_info *ip;
  214. uint32_t attr_len;
  215. uint8_t *attr;
  216. cf->methods_count = cnt = ReadU2(f);
  217. cf->methods = ip = SafeCalloc(cnt, sizeof(method_info));
  218. while(cnt-- > 0) {
  219. uint8_t *ptr;
  220. int ix, dix;
  221. ConstantPoolItem *cpi;
  222. ip->access_flags = ReadU2(f);
  223. ip->name_index = ReadU2(f);
  224. ip->descriptor_index = ReadU2(f);
  225. attr = NULL;
  226. attr_len = 0;
  227. ReadAttributes(f, cf, "Code", &attr_len, &attr, NULL);
  228. if (attr != NULL && attr_len > 0) {
  229. ix = 0;
  230. ip->max_stack = (attr[ix]<<8)+attr[ix+1];
  231. ix += 2;
  232. ip->max_locals = (attr[ix]<<8)+attr[ix+1];
  233. ix += 2;
  234. ip->code_length = (attr[ix]<<24)+(attr[ix+1]<<16)+
  235. (attr[ix+2]<<8)+attr[ix+3];
  236. ix += 4;
  237. if (ip->code_length > 0) {
  238. ip->code = ptr = SafeMalloc(ip->code_length);
  239. memcpy(ptr, attr+ix, ip->code_length);
  240. } else
  241. ip->code = NULL;
  242. ix += ip->code_length;
  243. ip->exception_table_length = (attr[ix]<<8) + attr[ix+1];
  244. ix += 2;
  245. if (ip->exception_table_length > 0) {
  246. ip->exception_table = ptr = SafeMalloc(ip->exception_table_length);
  247. memcpy(ptr, attr+ix, ip->exception_table_length);
  248. } else
  249. ip->exception_table = NULL;
  250. ix += ip->exception_table_length;
  251. ip->attributes_count = (attr[ix]<<8) + attr[ix+1];
  252. ix += 2;
  253. if (ip->attributes_count > 0) {
  254. ip->attributes = ptr = SafeMalloc(ip->attributes_count);
  255. memcpy(ptr, attr+ix, ip->attributes_count);
  256. } else
  257. ip->attributes = NULL;
  258. SafeFree(attr);
  259. }
  260. /* extra analysis needed for run-time */
  261. dix = ip->descriptor_index;
  262. cpi = &cf->cp_item[dix];
  263. ip->nArgs = CountParameters(cpi->sval+2);
  264. if (!(ip->access_flags & ACC_STATIC))
  265. ip->nArgs += 1;
  266. ip++;
  267. }
  268. }
  269. ClassFile *ReadClassFile( char *classname ) {
  270. FILE *f;
  271. ClassFile *result;
  272. char *filename;
  273. FileNameList fnp;
  274. filename = SafeMalloc(strlen(classname)+7);
  275. strcpy(filename,classname);
  276. strcat(filename,".class");
  277. // Check if we have already tried to read this file
  278. for( fnp = filesRead; fnp != NULL; fnp = fnp->next ) {
  279. if (strcmp(fnp->filename,filename) == 0) {
  280. SafeFree(filename);
  281. fnp->cnt++;
  282. return NULL; // we have tried to read it before
  283. }
  284. }
  285. fnp = SafeMalloc(sizeof(*fnp));
  286. fnp->filename = filename;
  287. fnp->cnt = 1;
  288. fnp->next = filesRead;
  289. filesRead = fnp;
  290. f = fopen(filename, "rb");
  291. if (f == NULL) {
  292. // Our interpreter simply does not support loading of built-in
  293. // classes, so suppress the error message in this case
  294. if (strncmp(filename, "java/", 5) != 0)
  295. fprintf(stderr, "Unable to read file %s\n", filename);
  296. return NULL;
  297. }
  298. if (ReadU4(f) != MagicNumber) {
  299. fprintf(stderr, "File %s does not begin with magic number\n", filename);
  300. exit(1);
  301. }
  302. result = SafeMalloc(sizeof(ClassFile));
  303. ReadU2(f); // minor version
  304. ReadU2(f); // major version
  305. ReadConstantPool(f,result);
  306. result->access_flags = ReadU2(f);
  307. result->this_class = ReadU2(f);
  308. result->super_class = ReadU2(f);
  309. ReadInterfaces(f,result);
  310. ReadFields(f,result);
  311. ReadMethods(f,result);
  312. ReadAttributes(f, result, NULL);
  313. result->cname = GetCPItemAsString(result,result->this_class);
  314. fclose(f);
  315. return result;
  316. }