int printtype(collection_type *collection_ptr,struct genhashtable *ght) { int j=0; int offset=0; int value=0; struct valuepair *vp=NULL; if (gencontains(ght,collection_ptr->name)) vp=(struct valuepair *)gengettable(ght,collection_ptr->name); if (vp!=NULL) collection_ptr=(collection_type*) dwarf_entry_array[vp->index].entry_ptr; for(j=0;j<collection_ptr->num_members;j++) { dwarf_entry *entry=collection_ptr->members[j]; if (entry->tag_name==DW_TAG_inheritance) { inherit * inherit_ptr=(inherit *)entry->entry_ptr; if (inherit_ptr->data_member_location>offset) { printf(" reserved byte[%ld];\n",inherit_ptr->data_member_location-offset); offset=inherit_ptr->data_member_location; } { dwarf_entry *type=inherit_ptr->target_ptr; collection_type *c_ptr=(collection_type*)type->entry_ptr; offset+=printtype(c_ptr,ght); } } else { member * member_ptr=(member *)entry->entry_ptr; char *name=member_ptr->name; char *newname=NULL; dwarf_entry *type=member_ptr->type_ptr; char *typestr=printname(type,GETTYPE); char *poststr=printname(type,POSTNAME); if (member_ptr->data_member_location>offset) { printf(" reserved byte[%ld];\n",member_ptr->data_member_location-offset); offset=member_ptr->data_member_location; } offset+=getsize(type); newname=escapestr(name); { char buf[512]; char *dtype; sprintf(buf, "%s.%s\0", collection_ptr->name,newname); if (arrayt!=NULL&&gencontains(arrayt, &buf)) { genputtable(arraytype, buf, typestr); dtype=deref(typestr); printf(" %s_array * %s%s;\n",dtype,newname,poststr); free(dtype); } else printf(" %s %s%s;\n",typestr,newname,poststr); } free(newname); } } return offset; }
struct rolemethod * methodaddtable(struct heap_state * heap , struct rolemethod *method) { if (gencontains(heap->methodtable, method)) { struct rolemethod * retval=gengettable(heap->methodtable, method); methodfree(method); return retval; } else { genputtable(heap->methodtable, method,method); return method; } }
// If the first basic block of a function ends before entryPC, use // the last instruction of that basic block as our entrypoint. Otherwise // use entryPC static void find_entry_pt(IRSB* bb_orig, FunctionEntry *f) { int i; Addr entry_pt = 0; if(gencontains(funcs_handled, f)) return; if (dyncomp_delayed_trace) { dyncomp_print_trace_info = True; dyncomp_delayed_trace = False; } if (dyncomp_delayed_print_IR) { fjalar_print_IR = True; dyncomp_delayed_print_IR = False; } FJALAR_DPRINTF("[find_entry_pt] Searching %s for entry address %x\n", f->fjalar_name, (UInt)f->entryPC); for(i=0 ; i < bb_orig->stmts_used; i++) { IRStmt *st = bb_orig->stmts[i]; if(st->tag == Ist_IMark) { FJALAR_DPRINTF("\tEncountered IMark for address %x\n", (UInt)st->Ist.IMark.addr); if(st->Ist.IMark.addr <= f->entryPC) { entry_pt = st->Ist.IMark.addr; } } } tl_assert( entry_pt ); FJALAR_DPRINTF("\t%x chosen for entry\n", (UInt)entry_pt); genputtable(funcs_handled, (void *)f, (void *)1); genputtable(FunctionTable_by_endOfBb, (void *)entry_pt, (void *)f); }
void mergerolechanges(struct heap_state *heap) { struct geniterator *it=gengetiterator(heap->methodlist->rolechangetable); while(1) { struct rolechange *rc=(struct rolechange *)gennext(it); struct method *method=heap->methodlist; int inner=2; if (rc==NULL) break; while(method!=NULL) { struct rolemethod *rm=method->rm; struct genhashtable * rolechanges=rm->rolechanges; struct rolechangesum *rcs=(struct rolechangesum *)calloc(1,sizeof(struct rolechangesum)); struct rolechangeheader *rch; struct effectregexpr *ere=NULL; struct rolechangepath *rcp; if (!(heap->options&OPTION_NORCEXPR)) ere=buildregexpr(method->pathtable, rc->uid); rcs->origrole=copystr(rc->origrole); rcs->newrole=copystr(rc->newrole); if (!gencontains(rolechanges, rcs)) { rch=(struct rolechangeheader *)calloc(1,sizeof(struct rolechangeheader)); if (inner) rch->inner=1; genputtable(rolechanges,rcs,rch); } else { rch=(struct rolechangeheader *) gengettable(rolechanges,rcs); if (inner) rch->inner=1; free(rcs->origrole); free(rcs->newrole); free(rcs); } /* rch points to appropriate rolechangeheader */ /* ere points to our regular expression */ rcp=rch->rcp; if (!(heap->options&OPTION_NORCEXPR)) { while(rcp!=NULL) { struct effectregexpr *ere2=rcp->expr; struct effectregexpr *erem=mergeeffectregexpr(ere,ere2); if (erem!=NULL) { rcp->expr=erem; if ((rcp->inner||inner)&&((inner==0)||(rcp->inner==0))) { rcp->inner=1; } /*Update count */ if ((rcp->exact+1)==rm->numberofcalls) rcp->exact=rm->numberofcalls; if (rcp->exact<rm->numberofcalls) rcp->exact=0; freeeffectregexpr(ere2); freeeffectregexpr(ere); break; } rcp=rcp->next; } if(rcp==NULL) { /* Couldn't merge in */ struct rolechangepath *rcp2=(struct rolechangepath *)calloc(1, sizeof(struct rolechangepath)); rcp2->expr=ere; if(rm->numberofcalls==1) rcp2->exact=1; rcp2->next=rch->rcp; rcp2->inner=inner; rch->rcp=rcp2; } } method=method->caller; inner=0; } free(rc->origrole); free(rc->newrole); free(rc); } genfreeiterator(it); genfreehashtable(heap->methodlist->rolechangetable); heap->methodlist->rolechangetable=NULL; }
void enter_function(FunctionEntry* f) { FunctionExecutionState* newEntry; extern FunctionExecutionState* curFunctionExecutionStatePtr; ThreadId tid = VG_(get_running_tid)(); Addr stack_ptr= VG_(get_SP)(tid); Addr frame_ptr = 0; /* E.g., %ebp */ int local_stack, size; FJALAR_DPRINTF("[enter_function] startPC is: %x, entryPC is: %x, cu_base: %p\n", (UInt)f->startPC, (UInt)f->entryPC,(void *)f->cuBase); FJALAR_DPRINTF("Value of edi: %lx, esi: %lx, edx: %lx, ecx: %lx\n", (long)VG_(get_xDI)(tid), (long)VG_(get_xSI)(tid), (long)VG_(get_xDX)(tid), (long)VG_(get_xCX)(tid)); // Determine the frame pointer for this function using DWARF // location lists. This is a "virtual frame pointer" in that it is // used by the DWARF debugging information in providing the address // of formal parameters and local variables, but it may or may not // correspond to an actual frame pointer in the architecture. For // example: This will not always return %xbp on x86{-64} platforms // and *SHOULD*(untested) work with the -fomit-frame-pointer flag in GCC // // It usually points just above the function return address. The // .debug_loc info tells how to find (calculate) the frame base // at any point in the program. (markro) if(f->locList) { Addr eip = f->entryPC; location_list *ll; eip = eip - f->cuBase; FJALAR_DPRINTF("\tCurrent EIP is: %x\n", (UInt)eip); FJALAR_DPRINTF("\tLocation list based function(offset from base: %x). offset is %lu\n",(UInt)eip, f->locListOffset); if (gencontains(loc_list_map, (void *)f->locListOffset)) { ll = gengettable(loc_list_map, (void *)f->locListOffset); // (comment added 2009) // HACK. g++ and GCC handle location lists differently. GCC puts lists offsets // relative to the compilation unit, g++ uses the actual address. I'm going to // compare the location list ranges both to the cu_base offset, as well as // the function's entry point. This might break if there's every a case // where the compilation unit offset is a valid address in the program while(ll && !(((ll->begin <= eip) && (ll->end >= eip)) || ((ll->begin <= f->entryPC) && (ll->end >= f->entryPC)))) { FJALAR_DPRINTF("\tExamining loc list entry: %x - %x - %x\n", (UInt)ll->offset, (UInt)ll->begin, (UInt)ll->end); ll = ll->next; } if(ll) { FJALAR_DPRINTF("\tFound location list entry, finding location corresponding to dwarf #: %d with offset: %lld\n", ll->atom, ll->atom_offset); // (comment added 2013) // It turns out it might not be just the contents of a register. Some // 32bit x86 code does some tricky stack alignment and has to save a // pointer to the orginal stack frame. This means we get passed a // DW_OP_deref instead of a DW_OP_breg. The tricky bit is we don't // want to go back to that address because it probably won't be equal // to the local frame pointer due to the stack alignment. So the HACK // is to just assume the frame pointer is at EBP+8 like normal. (markro) if (ll->atom == DW_OP_deref) { ll->atom = DW_OP_breg5; ll->atom_offset = 8; } if(get_reg[ll->atom - DW_OP_breg0]) { frame_ptr = (*get_reg[ll->atom - DW_OP_breg0])(tid) + ll->atom_offset; } } } } // This is the old code to determine the frame. Fallback to it if we don't // have a frame_base from the location_list path. This should keep GCC 3 working // fine. if(frame_ptr == 0) { if (f != primed_function) { printf("No location list or frame pointer giving up(Mangled name: %s)\n", f->mangled_name); return; } primed_function = 0; if (f->entryPC != f->startPC) { /* Prolog has run, so just use the real %ebp */ frame_ptr = VG_(get_FP)(VG_(get_running_tid)()); } else { FJALAR_DPRINTF("Faking prolog\n"); /* Don't know about prolog, so fake its effects, given we know that ESP hasn't yet been modified: */ // Looks like we never get here for amd64 as -4 is clearly wrong. (10/26/2015) frame_ptr = stack_ptr - 4; } } FJALAR_DPRINTF("\tEnter function: %s - StartPC: %p, EntryPC: %p, frame_ptr: %p\n", f->fjalar_name, (void *)f->startPC, (void *)f->entryPC, (void *)frame_ptr); newEntry = fnStackPush(tid); newEntry->func = f; newEntry->func->FP = frame_ptr; newEntry->func->lowestSP = stack_ptr; newEntry->FP = frame_ptr; newEntry->lowSP = stack_ptr; newEntry->lowestSP = stack_ptr; newEntry->xAX = 0; newEntry->xDX = 0; newEntry->FPU = 0; newEntry->invocation_nonce = cur_nonce++; newEntry->func->nonce = newEntry->invocation_nonce; // FJALAR VIRTUAL STACK // Fjalar maintains a virtual stack for invocation a function. This // allows Fjalar to provide tools with unaltered values of formal // parameters at both function entry and exit, regardless of whether // or not the compiler chooses to use the original formal parameter // locations as storage for local values. // Initialize virtual stack and copy parts of the Valgrind stack // into that virtual stack local_stack = frame_ptr - stack_ptr + VG_STACK_REDZONE_SZB; /* in our frame */ tl_assert(local_stack >= 0); FJALAR_DPRINTF("frame_ptr: %p, stack_ptr: %p, VG_STACK_REDZONE: %d\n", (void *)frame_ptr, (void *)stack_ptr, VG_STACK_REDZONE_SZB); // The virtual stack consists of: // (1) local_stack: the entirety of the function's local stack (the // memory between the frame pointer and the stack pointer (including the extra // redzone) // (2) The return pointer, which is sizeof(Addr) bytes // (3) The saved base pointer, which is sizeof(Addr) bytes // (4) All formal parameters passed on the stack, which is // f->formalParamStackByteSize bytes // Let's be conservative in how much we copy over to the Virtual stack. Due to the // stack alignment operations in main, we may need as much as 16 bytes over the above. size = local_stack + f->formalParamStackByteSize + sizeof(Addr)*2 + 32;/* plus stuff in caller's*/ FJALAR_DPRINTF("local_stack: %p, arg_size: %x\n", (void *)(frame_ptr - f->formalParamLowerStackByteSize), f->formalParamLowerStackByteSize); int delta = stack_ptr - (frame_ptr - f->formalParamLowerStackByteSize); if (delta < 0 ) delta = 0; tl_assert(size >= 0); if (size != 0) { newEntry->virtualStack = VG_(calloc)("fjalar_main.c: enter_func", size, sizeof(char)); newEntry->virtualStackByteSize = size; newEntry->virtualStackFPOffset = local_stack; clear_all_tags_in_range(stack_ptr - VG_STACK_REDZONE_SZB, VG_STACK_REDZONE_SZB - delta); VG_(memcpy)(newEntry->virtualStack, (char*)stack_ptr - VG_STACK_REDZONE_SZB, size); // VERY IMPORTANT!!! Copy all the A & V bits over the real stack to // virtualStack!!! (As a consequence, this copies over the tags // as well - look in mc_main.c). Note that the way do this means // that the copy is now guest-accessible, if they guessed the // VG_(calloc)ed address, which is a bit weird. It would be more // elegant to copy the metadata to an inaccessible place, but that // would be more work. FJALAR_DPRINTF("Copying over stack [%p] -> [%p] %d bytes\n",(void *)(stack_ptr - VG_STACK_REDZONE_SZB), (void *)newEntry->virtualStack, size); mc_copy_address_range_state(stack_ptr - VG_STACK_REDZONE_SZB, (Addr)(newEntry->virtualStack), size); newEntry->func->guestStackStart = stack_ptr - VG_STACK_REDZONE_SZB; newEntry->func->guestStackEnd = newEntry->func->guestStackStart + size; newEntry->func->lowestVirtSP = (Addr)newEntry->virtualStack; } else { printf("Obtained a stack size of 0 for Function: %s. Aborting\n", f->fjalar_name); tl_assert(0); } // Do this AFTER initializing virtual stack and lowestSP curFunctionExecutionStatePtr = newEntry; fjalar_tool_handle_function_entrance(newEntry); }
void initializeTypeArray() { int i; dwarf_entry * cur_entry; struct genhashtable * ght=genallocatehashtable((unsigned int (*)(void *)) & hashstring,(int (*)(void *,void *)) &equivalentstrings); struct genhashtable * sht=NULL; if (rootfile!=NULL) { char buf[512]; char a; int fd=open(rootfile,O_RDONLY); int offset=0; sht=genallocatehashtable((unsigned int (*)(void *)) & hashstring,(int (*)(void *,void *)) &equivalentstrings); while(1) { if (read(fd,&a,1)>0) { if (a!=13&&a!=10) buf[offset++]=a; } else break; if (offset>0&&(a==13||a==10)) { buf[offset++]=0; { char *str=copystr(buf); genputtable(sht,str,str); } offset=0; } } } if (arrayfile!=NULL) { char buf[512]; char sizebuf[512]; char a; int fd=open(arrayfile,O_RDONLY); int offset=0; int readmore=1; int state=0; arrayt=genallocatehashtable((unsigned int (*)(void *)) & hashstring,(int (*)(void *,void *)) &equivalentstrings); arraytype=genallocatehashtable((unsigned int (*)(void *)) & hashstring,(int (*)(void *,void *)) &equivalentstrings); while(readmore) { if (read(fd,&a,1)<=0) readmore=0; if (readmore) { if (a==' ') { state=1; buf[offset]=0; offset=0; } else if (a!=13&&a!=10) { if (state==0) buf[offset++]=a; else sizebuf[offset++]=a; } } if ((state==1)&&offset>0&&(a==13||a==10||!readmore)) { state=0; sizebuf[offset]=0; { char *str=copystr(buf); char *sizestr=copystr(sizebuf); genputtable(arrayt,str,sizestr); } offset=0; } } } /* Assign names */ for (i = 0; i < dwarf_entry_array_size; i++) { cur_entry = &dwarf_entry_array[i]; if (entry_is_type(cur_entry)) { collection_type* collection_ptr = (collection_type*)(cur_entry->entry_ptr); int j=0; int offset=0; int value=0; for(j=0;j<collection_ptr->num_members;j++) { dwarf_entry *entry=collection_ptr->members[j]; if (entry->tag_name==DW_TAG_inheritance) { value++; } else { member * member_ptr=(member *)entry->entry_ptr; char *name=member_ptr->name; dwarf_entry *type=member_ptr->type_ptr; char *typestr=printname(type,GETTYPE); char *poststr=printname(type,POSTNAME); if (typestr!=NULL) value++; } } } } for (i = 0; i < dwarf_entry_array_size; i++) { cur_entry = &dwarf_entry_array[i]; if (entry_is_type(cur_entry)) { collection_type* collection_ptr = (collection_type*)(cur_entry->entry_ptr); int j=0; int offset=0; int value=0; for(j=0;j<collection_ptr->num_members;j++) { dwarf_entry *entry=collection_ptr->members[j]; if (entry->tag_name==DW_TAG_inheritance) { value++; } else { member * member_ptr=(member *)entry->entry_ptr; char *name=member_ptr->name; dwarf_entry *type=member_ptr->type_ptr; char *typestr=printname(type,GETTYPE); char *poststr=printname(type,POSTNAME); if (typestr!=NULL) value++; } } if (collection_ptr->name!=NULL) { struct valuepair *vp=NULL; if (gencontains(ght,collection_ptr->name)) vp=(struct valuepair *)gengettable(ght,collection_ptr->name); if (vp==NULL||vp->value<value) { if (vp==NULL) { vp=(struct valuepair*)calloc(1,sizeof(struct valuepair)); genputtable(ght,collection_ptr->name,vp); } vp->value=value; vp->index=i; } } } } assigntype=1; if (sht!=NULL) { int repeat=1; while(repeat) { repeat=0; for (i = 0; i < dwarf_entry_array_size; i++) { cur_entry = &dwarf_entry_array[i]; if (entry_is_type(cur_entry)) { collection_type* collection_ptr = (collection_type*)(cur_entry->entry_ptr); int j=0; int offset=0; int value=0; if (!gencontains(sht,collection_ptr->name)) continue; if (gencontains(ght,collection_ptr->name)) { struct valuepair *vp=(struct valuepair*)gengettable(ght,collection_ptr->name); if (vp->index!=i) continue; } for(j=0;j<collection_ptr->num_members;j++) { dwarf_entry *entry=collection_ptr->members[j]; if (entry->tag_name==DW_TAG_inheritance) { inherit *in_ptr=(inherit*)collection_ptr->members[j]->entry_ptr; dwarf_entry *typeptr=in_ptr->target_ptr; collection_type* sub_ptr = (collection_type*)(typeptr->entry_ptr); if (!gencontains(sht,sub_ptr->name)) { repeat=1; genputtable(sht,sub_ptr->name,sub_ptr->name); } } else { member * member_ptr=(member *)entry->entry_ptr; char *name=member_ptr->name; dwarf_entry *type=member_ptr->type_ptr; char *typestr=printname(type,GETJUSTTYPE); if (typestr!=NULL&&!gencontains(sht,typestr)) { repeat=1; genputtable(sht,typestr,typestr); } } } } } } } for (i = 0; i < dwarf_entry_array_size; i++) { cur_entry = &dwarf_entry_array[i]; if (entry_is_type(cur_entry)) { collection_type* collection_ptr = (collection_type*)(cur_entry->entry_ptr); int j=0; int offset=0; if (collection_ptr->name==NULL) continue; if (sht!=NULL&&!gencontains(sht,collection_ptr->name)) continue; if (gencontains(ght,collection_ptr->name)) { struct valuepair *vp=(struct valuepair*)gengettable(ght,collection_ptr->name); if (vp->index!=i) continue; } j=0; printf("structure %s ",collection_ptr->name); while(j<collection_ptr->num_members&& collection_ptr->members[j]->tag_name==DW_TAG_inheritance) { inherit *in_ptr=(inherit*)collection_ptr->members[j]->entry_ptr; dwarf_entry *typeptr=in_ptr->target_ptr; collection_type* sub_ptr = (collection_type*)(typeptr->entry_ptr); if (j==0) printf("subclass of "); else printf(", "); printf("%s ",sub_ptr->name); j++; } printf("{ \n"); for(j=0;j<collection_ptr->num_members;j++) { dwarf_entry *entry=collection_ptr->members[j]; if (entry->tag_name==DW_TAG_inheritance) { inherit * inherit_ptr=(inherit *)entry->entry_ptr; if (inherit_ptr->data_member_location>offset) { printf(" reserved byte[%ld];\n",inherit_ptr->data_member_location-offset); offset=inherit_ptr->data_member_location; } { dwarf_entry *type=inherit_ptr->target_ptr; collection_type *c_ptr=(collection_type*)type->entry_ptr; offset+=printtype(c_ptr,ght); } } else { member * member_ptr=(member *)entry->entry_ptr; char *name=member_ptr->name; dwarf_entry *type=member_ptr->type_ptr; char *typestr=printname(type,GETTYPE); char *poststr=printname(type,POSTNAME); char *newname=NULL; if (member_ptr->data_member_location>offset) { printf(" reserved byte[%ld];\n",member_ptr->data_member_location-offset); offset=member_ptr->data_member_location; } offset+=getsize(type); newname=escapestr(name); { char buf[512]; char *dtype; sprintf(buf, "%s.%s\0", collection_ptr->name,newname); if (arrayt!=NULL&&gencontains(arrayt, &buf)) { genputtable(arraytype, copystr(buf), typestr); dtype=deref(typestr); printf(" %s_array * %s%s;\n",dtype,newname,poststr); free(dtype); } else printf(" %s %s%s;\n",typestr,newname,poststr); } free(newname); } } if (offset<collection_ptr->byte_size) printf(" reserved byte[%ld];\n",collection_ptr->byte_size-offset); printf("}\n\n"); } } if (arrayt!=NULL) { struct geniterator * gi=gengetiterator(arrayt); while(1) { char * str=(char *)gennext(gi); char *size=NULL; char *typestr=NULL; if (str==NULL) break; size=(char *)gengettable(arrayt,str); typestr=deref((char *)gengettable(arraytype,str)); printf("structure %s_array {\n",typestr); printf(" %s elem[%s];\n",typestr,size); printf("}\n"); free(typestr); } genfreeiterator(gi); } }
void fastscan() { struct methodchain *methodstack=NULL; struct namer *namer=allocatenamer(); struct genhashtable *calltable=genallocatehashtable((int (*)(void *)) &hashmethod, (int (*)(void *,void *)) &comparemethod); struct genhashtable *statictable=genallocatehashtable((int (*)(void *)) &hashmethod, (int (*)(void *,void *)) &comparemethod); while(1) { char *line=getline(); #ifdef DEBUG printf("------------------------------------------------------\n"); #endif if (line==0) { outputinfo(namer, calltable,statictable); return; } #ifdef DEBUG printf("[%s]\n",line); #endif switch(line[0]) { case 'C': break; case 'O': break; case 'N': { /* Natively created object...may not have pointer to it*/ char buf[1000]; sscanf(line,"NI: %s",buf); getclass(namer,buf); } break; case 'U': { /* New object*/ char buf[1000]; sscanf(line,"UI: %s",buf); getclass(namer,buf); } break; case 'K': break; case 'L': /* Do Load */ { struct localvars * lv=(struct localvars *) calloc(1, sizeof(struct localvars)); long long uid, objuid; char fieldname[600], classname[600], fielddesc[600]; sscanf(line,"LF: %s %ld %s %lld %s %s %s %lld",lv->name,&lv->linenumber, lv->sourcename, &objuid, classname, fieldname, fielddesc, &uid); getfield(namer,classname, fieldname,fielddesc); } break; case 'G': /* Do Array Load */ break; case 'M': /* Mark Local*/ break; case 'I': /* Enter Method*/ { struct methodchain* methodchain=(struct methodchain *) calloc(1,sizeof(struct methodchain)); char classname[600], methodname[600],signature[600]; int isStatic; sscanf(line,"IM: %s %s %s %d", classname, methodname, signature, &isStatic); methodchain->method=getmethod(namer, classname, methodname, signature); methodchain->caller=methodstack; if (!gencontains(statictable, methodchain->method)) { int * staticflag=(int *)malloc(sizeof (int)); *staticflag=isStatic; genputtable(statictable, methodchain->method, staticflag); } if (methodstack!=NULL) { if (!gencontains(calltable, methodchain->method)) { struct methodchain *mc=(struct methodchain *) calloc(1,sizeof(struct methodchain)); mc->method=methodstack->method; genputtable(calltable, methodchain->method, mc); } else { struct methodchain *tosearch=(struct methodchain *)gengettable(calltable, methodchain->method); while(tosearch->method!=methodstack->method) { if (tosearch->caller==NULL) { struct methodchain *mc=(struct methodchain *) calloc(1,sizeof(struct methodchain)); mc->method=methodstack->method; tosearch->caller=mc; break; } tosearch=tosearch->caller; } } } methodstack=methodchain; } break; case 'R': /* Return from method */ { struct methodchain* caller=methodstack->caller; free(methodstack); methodstack=caller; } break; case 'F': /* Field Assignment */ { long long suid; long long duid; char classname[1000]; char fieldname[1000]; char descname[1000]; sscanf(line,"FA: %lld %s %s %s %lld", &suid, classname, fieldname, descname, &duid); getfield(namer, classname, fieldname, descname); } break; case 'A': /* Array Assignment */ { long long suid; long long duid; long index; sscanf(line,"AA: %lld %ld %lld", &suid, &index, &duid); } break; } free(line); } }