Tree asgntree(int op, Tree l, Tree r) { Type aty, ty; r = pointer(r); ty = assign(l->type, r); if (ty) r = cast(r, ty); else { typeerror(ASGN, l, r); if (r->type == voidtype) r = retype(r, inttype); ty = r->type; } if (l->op != FIELD) l = lvalue(l); aty = l->type; if (isptr(aty)) aty = unqual(aty)->type; if (isconst(aty) || (isstruct(aty) && unqual(aty)->u.sym->u.s.cfields)) { if (isaddrop(l->op) && !l->u.sym->computed && !l->u.sym->generated) error("assignment to const identifier `%s'\n", l->u.sym->name); else error("assignment to const location\n"); } if (l->op == FIELD) { long n = 8 * l->u.field->type->size - fieldsize(l->u.field); if (n > 0 && isunsigned(l->u.field->type)) r = bittree(BAND, r, cnsttree(r->type, (unsigned long)fieldmask(l->u.field))); else if (n > 0) { if (r->op == CNST + I) { n = r->u.v.i; if (n & (1 << (fieldsize(l->u.field) - 1))) n |= ~0UL << fieldsize(l->u.field); r = cnsttree(r->type, n); } else r = shtree(RSH, shtree(LSH, r, cnsttree(inttype, n)), cnsttree(inttype, n)); } } if (isstruct(ty) && isaddrop(l->op) && iscallb(r)) return tree(RIGHT, ty, tree(CALL + B, ty, r->kids[0]->kids[0], l), idtree(l->u.sym)); return tree(mkop(op, ty), ty, l, r); }
static void assign(Node *n) { Node *l, *r; int op; op = n->Assign.op; l = n->Assign.l; r = n->Assign.r; if(op == '=') { expr(r); pushq("rax"); addr(l); popq("rcx"); if(!isptr(l->type) && !isitype(l->type) && !isstruct(l->type)) errorf("unimplemented assign\n"); store(l->type); outi("movq %%rcx, %%rax\n"); return; } addr(l); pushq("rax"); load(l->type); pushq("rax"); expr(r); outi("movq %%rax, %%rcx\n"); popq("rax"); /* XXX this type is not correct for comparison ops works anyway, but should be changed*/ obinop(op, n->type); outi("movq %%rax, %%rcx\n"); popq("rax"); store(l->type); outi("movq %%rcx, %%rax\n"); }
void retcode(Tree p) { Type ty; if (p == NULL) { if (events.returns) apply(events.returns, cfunc, NULL); return; } p = pointer(p); ty = assign(freturn(cfunc->type), p); if (ty == NULL) { error("illegal return type; found `%t' expected `%t'\n", p->type, freturn(cfunc->type)); return; } p = cast(p, ty); if (retv) { if (iscallb(p)) p = tree(RIGHT, p->type, tree(CALL+B, p->type, p->kids[0]->kids[0], idtree(retv)), rvalue(idtree(retv))); else { Type ty = retv->type->type; assert(isstruct(ty)); if (ty->u.sym->u.s.cfields) { ty->u.sym->u.s.cfields = 0; p = asgntree(ASGN, rvalue(idtree(retv)), p); ty->u.sym->u.s.cfields = 1; } else p = asgntree(ASGN, rvalue(idtree(retv)), p); } walk(p, 0, 0); if (events.returns) apply(events.returns, cfunc, rvalue(idtree(retv))); return; } if (events.returns) { Symbol t1 = genident(AUTO, p->type, level); addlocal(t1); walk(asgn(t1, p), 0, 0); apply(events.returns, cfunc, idtree(t1)); p = idtree(t1); } if (!isfloat(p->type)) p = cast(p, promote(p->type)); if (isptr(p->type)) { Symbol q = localaddr(p); if (q && (q->computed || q->generated)) warning("pointer to a %s is an illegal return value\n", q->scope == PARAM ? "parameter" : "local"); else if (q) warning("pointer to %s `%s' is an illegal return value\n", q->scope == PARAM ? "parameter" : "local", q->name); } walk(tree(mkop(RET,p->type), p->type, p, NULL), 0, 0); }
static void load(CTy *t) { if(isitype(t) || isptr(t)) { switch(t->size) { case 8: outi("movq (%%rax), %%rax\n"); break; case 4: outi("movslq (%%rax), %%rax\n"); break; case 2: outi("movswq (%%rax), %%rax\n"); break; case 1: outi("movsbq (%%rax), %%rax\n"); break; default: panic("internal error\n"); } return; } if(isstruct(t)) { return; } if(isarray(t)) { return; } if(isfunc(t)) { return; } errorf("unimplemented load %d\n", t->t); }
void emitsym(Sym *sym) { out("# emit sym %s\n", sym->name); switch(sym->k){ case SYMGLOBAL: if(sym->Global.sclass == SCEXTERN) break; if(isfunc(sym->type)) { func(sym->init, sym->Global.label, sym->Global.sclass == SCGLOBAL); break; } penddata(sym->Global.label, sym->type, sym->init, sym->Global.sclass == SCGLOBAL); break; case SYMLOCAL: if(sym->init) { expr(sym->init); pushq("rax"); outi("leaq %d(%%rbp), %%rax\n", sym->Local.slot->offset); popq("rcx"); if(!isptr(sym->type) && !isitype(sym->type) && !isstruct(sym->type)) errorf("unimplemented init\n"); store(sym->type); } break; case SYMENUM: case SYMTYPE: panic("internal error"); } out("\n"); }
void function(sSymbol_t f, sSymbol_t caller[], sSymbol_t callee[], int ncalls) { int i; localsize=offset=tmpsize=nbregs=0; funame=f->x.name; for (i=8;i<32;i++) temp[i]->x.name="******"; for (i = 0; caller[i] && callee[i]; i++) { caller[i]->x.name=stringf("(ap),%d",offset); caller[i]->x.adrmode='A'; offset+=caller[i]->type->size; if (optimizelevel>1 && callee[i]->sclass==REGISTER && allocreg(callee[i])) ; /* allocreg ok */ else { callee[i]->x.adrmode=caller[i]->x.adrmode; callee[i]->x.name=caller[i]->x.name; callee[i]->sclass=AUTO; } } busy=localsize=0; offset=6; gencode(caller,callee); omit_frame=(i==0 && localsize==6); print("%s\n",funame); if (optimizelevel>1 && omit_frame && nbregs==0) ; else print("\tENTER(%d,%d)\n",nbregs,localsize); if (isstruct(freturn(f->type))) print("\tMOVW_DI(op1,(fp),6)\n"); emitcode(); }
static void fields(node_t * sym) { int follow[] = {INT, CONST, '}', IF, 0}; node_t *sty = SYM_TYPE(sym); if (!first_decl(token)) { error("expect type name or qualifiers"); return; } struct vector *v = vec_new(); do { node_t *basety = specifiers(NULL, NULL); for (;;) { node_t *field = new_field(); if (token->id == ':') { bitfield(field); FIELD_TYPE(field) = basety; } else { node_t *ty = NULL; struct token *id = NULL; declarator(&ty, &id, NULL); attach_type(&ty, basety); if (token->id == ':') bitfield(field); FIELD_TYPE(field) = ty; if (id) { for (int i = 0; i < vec_len(v); i++) { node_t *f = vec_at(v, i); if (FIELD_NAME(f) && !strcmp(FIELD_NAME(f), id->name)) { errorf(id->src, "redefinition of '%s'", id->name); break; } } FIELD_NAME(field) = id->name; AST_SRC(field) = id->src; } } vec_push(v, field); if (token->id != ',') break; expect(','); ensure_field(field, vec_len(v), false); } match(';', follow); ensure_field(vec_tail(v), vec_len(v), isstruct(sty) && !first_decl(token)); } while (first_decl(token)); TYPE_FIELDS(sty) = (node_t **) vtoa(v); set_typesize(sty); }
/* dbxout - output .stabs entry for type ty */ static void dbxout(Type ty) { ty = unqual(ty); if (!ty->x.printed) { int col = 0; print(".stabs \""), col += 8; if (ty->u.sym && !(isfunc(ty) || isarray(ty) || isptr(ty))) print("%s", ty->u.sym->name), col += strlen(ty->u.sym->name); print(":%c", isstruct(ty) || isenum(ty) ? 'T' : 't'), col += 2; emittype(ty, 0, col); print("\",%d,0,0,0\n", N_LSYM); } }
static void addr(Node *n) { int sz; int offset; Sym *sym; switch(n->t) { case NUNOP: expr(n->Unop.operand); break; case NSEL: expr(n->Sel.operand); if(isptr(n->Sel.operand->type)) offset = structoffsetfromname(n->Sel.operand->type->Ptr.subty, n->Sel.name); else if(isstruct(n->Sel.operand->type)) offset = structoffsetfromname(n->Sel.operand->type, n->Sel.name); else panic("internal error"); if(offset < 0) panic("internal error"); outi("addq $%d, %%rax\n", offset); break; case NIDENT: sym = n->Ident.sym; switch(sym->k) { case SYMGLOBAL: outi("leaq %s(%%rip), %%rax\n", sym->Global.label); break; case SYMLOCAL: outi("leaq %d(%%rbp), %%rax\n", sym->Local.slot->offset); break; default: panic("internal error"); } break; case NIDX: expr(n->Idx.idx); sz = n->type->size; if(sz != 1) { outi("imul $%d, %%rax\n", sz); } pushq("rax"); expr(n->Idx.operand); popq("rcx"); outi("addq %%rcx, %%rax\n"); break; default: errorf("unimplemented addr\n"); } }
static void data(Data *d) { InitMember *initmemb; int i, offset; char *l; if(!d->init) { out(".comm %s, %d, %d\n", d->label, d->type->size, d->type->align); return; } if(d->isglobal) out(".globl %s\n", d->label); out("%s:\n", d->label); if(ischararray(d->type)) if(d->init->t == NSTR) { out(".string %s\n", d->init->Str.v); return; } if(ischarptr(d->type)) if(d->init->t == NSTR) { l = newlabel(); out(".quad %s\n", l); out("%s:\n", l); out(".string %s\n", d->init->Str.v); return; } if(isitype(d->type) || isptr(d->type)) { itypedata(d->init); return; } if(isarray(d->type) || isstruct(d->type)) { if(d->init->t != NINIT) errorposf(&d->init->pos, "array/struct expects a '{' style initializer"); offset = 0; for(i = 0; i < d->init->Init.inits->len ; i++) { initmemb = vecget(d->init->Init.inits, i); if(initmemb->offset != offset) out(".fill %d, 1, 0\n", initmemb->offset - offset); itypedata(initmemb->n); offset = initmemb->offset + initmemb->n->type->size; } if(offset < d->type->size) out(".fill %d, 1, 0\n", d->type->size - offset); return; } panic("internal error"); }
void addstructmember(SrcPos *pos, CTy *t, char *name, CTy *membt) { StructMember *sm, *subsm; int i, align, sz; sm = gcmalloc(sizeof(StructMember)); sm->name = name; sm->type = membt; if(!isstruct(t)) panic("internal error"); if(sm->name == 0 && isstruct(sm->type)) { for(i = 0; i < sm->type->Struct.members->len; i++) { subsm = vecget(sm->type->Struct.members, i); addstructmember(pos, t, subsm->name, subsm->type); } return; } if(sm->name) { for(i = 0; i < t->Struct.members->len; i++) { subsm = vecget(t->Struct.members, i); if(subsm->name) if(strcmp(sm->name, subsm->name) == 0) errorposf(pos ,"struct already has a member named %s", sm->name); } } if(membt->align < t->align) t->align = membt->align; sz = t->size; align = membt->align; if(sz % align) sz = sz + align - (sz % align); sm->offset = sz; sz += sm->type->size; t->size = sz; vecappend(t->Struct.members, sm); }
/* asgn - generate tree for assignment of expr e to symbol p sans qualifiers */ Tree asgn(Symbol p, Tree e) { if (isarray(p->type)) e = tree(ASGN+B, p->type, idtree(p), tree(INDIR+B, e->type, e, NULL)); else { Type ty = p->type; p->type = unqual(p->type); if (isstruct(p->type) && p->type->u.sym->u.s.cfields) { p->type->u.sym->u.s.cfields = 0; e = asgntree(ASGN, idtree(p), e); p->type->u.sym->u.s.cfields = 1; } else e = asgntree(ASGN, idtree(p), e); p->type = ty; } return e; }
StructMember * getstructmember(CTy *t, char *n) { int i; StructMember *sm; if(isptr(t)) t = t->Ptr.subty; if(!isstruct(t)) panic("internal error"); for(i = 0; i < t->Struct.members->len; i++) { sm = vecget(t->Struct.members, i); if(strcmp(n, sm->name) == 0) return sm; } return 0; }
/* stabsym - output a stab entry for symbol p */ void stabsym(Symbol p) { int code, tc, sz = p->type->size; if (p->generated || p->computed) return; if (isfunc(p->type)) { print(".stabs \"%s:%c%d\",%d,0,0,%s\n", p->name, p->sclass == STATIC ? 'f' : 'F', dbxtype(freturn(p->type)), N_FUN, p->x.name); return; } if (!IR->wants_argb && p->scope == PARAM && p->structarg) { assert(isptr(p->type) && isstruct(p->type->type)); tc = dbxtype(p->type->type); sz = p->type->type->size; } else tc = dbxtype(p->type); if (p->sclass == AUTO && p->scope == GLOBAL || p->sclass == EXTERN) { print(".stabs \"%s:G", p->name); code = N_GSYM; } else if (p->sclass == STATIC) { print(".stabs \"%s:%c%d\",%d,0,0,%s\n", p->name, p->scope == GLOBAL ? 'S' : 'V', tc, p->u.seg == BSS ? N_LCSYM : N_STSYM, p->x.name); return; } else if (p->sclass == REGISTER) { if (p->x.regnode) { int r = p->x.regnode->number; if (p->x.regnode->set == FREG) r += 32; /* floating point */ print(".stabs \"%s:%c%d\",%d,0,", p->name, p->scope == PARAM ? 'P' : 'r', tc, N_RSYM); print("%d,%d\n", sz, r); } return; } else if (p->scope == PARAM) { print(".stabs \"%s:p", p->name); code = N_PSYM; } else if (p->scope >= LOCAL) { print(".stabs \"%s:", p->name); code = N_LSYM; } else assert(0); print("%d\",%d,0,0,%s\n", tc, code, p->scope >= PARAM && p->sclass != EXTERN ? p->x.name : "0"); }
static void sel(Node *n) { CTy *t; int offset; expr(n->Sel.operand); t = n->Sel.operand->type; if(isptr(t)) offset = structoffsetfromname(t->Ptr.subty, n->Sel.name); else if(isstruct(t)) offset = structoffsetfromname(t, n->Sel.name); else panic("internal error"); if(offset < 0) panic("internal error"); if(offset != 0) outi("add $%d, %%rax\n", offset); load(n->type); }
Tree calltree(Tree f, Type ty, Tree args, Symbol t3) { Tree p; if (args) f = tree(RIGHT, f->type, args, f); if (isstruct(ty)) assert(t3), p = tree(RIGHT, ty, tree(CALL+B, ty, f, addrof(idtree(t3))), idtree(t3)); else { Type rty = ty; if (isenum(ty)) rty = unqual(ty)->type; if (!isfloat(rty)) rty = promote(rty); p = tree(mkop(CALL, rty), rty, f, NULL); if (isptr(ty) || p->type->size > ty->size) p = cast(p, ty); } return p; }
Type assign(Type xty, Tree e) { Type yty = unqual(e->type); xty = unqual(xty); if (isenum(xty)) xty = xty->type; if (xty->size == 0 || yty->size == 0) return NULL; if ( isarith(xty) && isarith(yty) || isstruct(xty) && xty == yty) return xty; if (isptr(xty) && isnullptr(e)) return xty; if ((isvoidptr(xty) && isptr(yty) || isptr(xty) && isvoidptr(yty)) && ( (isconst(xty->type) || !isconst(yty->type)) && (isvolatile(xty->type) || !isvolatile(yty->type)))) return xty; if ((isptr(xty) && isptr(yty) && eqtype(unqual(xty->type), unqual(yty->type), 1)) && ( (isconst(xty->type) || !isconst(yty->type)) && (isvolatile(xty->type) || !isvolatile(yty->type)))) return xty; if (isptr(xty) && isptr(yty) && ( (isconst(xty->type) || !isconst(yty->type)) && (isvolatile(xty->type) || !isvolatile(yty->type)))) { Type lty = unqual(xty->type), rty = unqual(yty->type); if (isenum(lty) && rty == inttype || isenum(rty) && lty == inttype) { if (Aflag >= 1) warning("assignment between `%t' and `%t' is compiler-dependent\n", xty, yty); return xty; } } return NULL; }
static void store(CTy *t) { if(isitype(t) || isptr(t)) { switch(t->size) { case 8: outi("movq %%rcx, (%%rax)\n"); break; case 4: outi("movl %%ecx, (%%rax)\n"); break; case 2: outi("movw %%cx, (%%rax)\n"); break; case 1: outi("movb %%cl, (%%rax)\n"); break; default: panic("internal error\n"); } return; } if(isstruct(t)) { pushq("rdi"); pushq("rsi"); pushq("rcx"); outi("movq %%rcx, %%rsi\n"); outi("movq %%rax, %%rdi\n"); outi("movq $%d, %%rcx\n", t->size); outi("rep movsb\n"); popq("rcx"); popq("rsi"); popq("rdi"); return; } errorf("unimplemented store\n"); }
Tree call(Tree f, Type fty, Coordinate src) { int n = 0; Tree args = NULL, r = NULL, e; Type *proto, rty = unqual(freturn(fty)); Symbol t3 = NULL; if (fty->u.f.oldstyle) proto = NULL; else proto = fty->u.f.proto; if (hascall(f)) r = f; if (isstruct(rty)) { t3 = temporary(AUTO, unqual(rty)); if (rty->size == 0) error("illegal use of incomplete type `%t'\n", rty); } if (t != ')') for (;;) { Tree q = pointer(expr1(0)); if (proto && *proto && *proto != voidtype) { Type aty; q = value(q); aty = assign(*proto, q); if (aty) q = cast(q, aty); else error("type error in argument %d to %s; found `%t' expected `%t'\n", n + 1, funcname(f), q->type, *proto); if ((isint(q->type) || isenum(q->type)) && q->type->size != inttype->size) q = cast(q, promote(q->type)); ++proto; } else { if (!fty->u.f.oldstyle && *proto == NULL) error("too many arguments to %s\n", funcname(f)); q = value(q); if (isarray(q->type) || q->type->size == 0) error("type error in argument %d to %s; `%t' is illegal\n", n + 1, funcname(f), q->type); else q = cast(q, promote(q->type)); } if (!IR->wants_argb && isstruct(q->type)) if (iscallb(q)) q = addrof(q); else { Symbol t1 = temporary(AUTO, unqual(q->type)); q = asgn(t1, q); q = tree(RIGHT, ptr(t1->type), root(q), lvalue(idtree(t1))); } if (q->type->size == 0) q->type = inttype; if (hascall(q)) r = r ? tree(RIGHT, voidtype, r, q) : q; args = tree(mkop(ARG, q->type), q->type, q, args); n++; if (Aflag >= 2 && n == 32) warning("more than 31 arguments in a call to %s\n", funcname(f)); if (t != ',') break; t = gettok(); } expect(')'); if (proto && *proto && *proto != voidtype) error("insufficient number of arguments to %s\n", funcname(f)); if (r) args = tree(RIGHT, voidtype, r, args); e = calltree(f, rty, args, t3); if (events.calls) apply(events.calls, &src, &e); return e; }
//function(..) module saved jan 1 2013 as part of prep for scrt integration static void function(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { int i, saved, sizefsave, sizeisave, varargs; Symbol r, argregs[NUM_ARG_REGS]; usedmask[0] = usedmask[1] = 0; freemask[0] = freemask[1] = ~(unsigned)0; offset = maxoffset = maxargoffset = 0; for (i = 0; callee[i]; i++) //find last argument ; varargs = variadic(f->type) //see if variable arguments by type or by name of final argument || i > 0 && strcmp(callee[i-1]->name, "va_alist") == 0; for (i = 0; callee[i]; i++) { //for each argument Symbol p = callee[i]; Symbol q = caller[i]; assert(q); offset = roundup(offset, q->type->align); //calculate the offset from the caller's sp p->x.offset = q->x.offset = offset; p->x.name = q->x.name = stringd(offset); r = argreg(i, offset, optype(ttob(q->type)), q->type->size, optype(ttob(caller[0]->type))); if (i < NUM_ARG_REGS) argregs[i] = r; offset = roundup(offset + q->type->size, 2); //i dunno if (varargs) p->sclass = AUTO; //variable args are always auto? else if (r && ncalls == 0 && //I dunno !isstruct(q->type) && !p->addressed && !(isfloat(q->type) && r->x.regnode->set == IREG)) { p->sclass = q->sclass = REGISTER; askregvar(p, r); assert(p->x.regnode && p->x.regnode->vbl == p); q->x = p->x; q->type = p->type; } else if (askregvar(p, rmap(ttob(p->type))) && r != NULL && (isint(p->type) || p->type == q->type)) { assert(q->sclass != REGISTER); p->sclass = q->sclass = REGISTER; q->type = p->type; } } assert(!caller[i]); //done with arguments, their individual offsets and maxargoffset have been set offset = 0; gencode(caller, callee); if (ncalls) //prepare to save return address if necessary(i.e. we do calls of our own) usedmask[IREG] |= ((unsigned)1)<<REG_RETADDR; usedmask[IREG] &= INT_CALLEE_SAVE; //limit saving to those we're responsible for usedmask[FREG] &= 0xfff00000; maxargoffset = roundup(maxargoffset, usedmask[FREG] ? 8 : 2); if (ncalls && maxargoffset < NUM_ARG_REGS*2) maxargoffset = NUM_ARG_REGS*2; sizefsave = 4*bitcount(usedmask[FREG]); //space needed to save the float regs sizeisave = 2*bitcount(usedmask[IREG]); //space needed to save the int regs framesize = roundup(maxargoffset + sizefsave //space for outgoing arguments, space for saving floats, + sizeisave + maxoffset, 2); //space for saving ints, space for locals //segment(CODE); //printf("\talign 16\n"); printf("%s:\n", f->x.name); i = maxargoffset + sizefsave - framesize; //I dunno but it's -v and it's never used! if (framesize > 0) print("\talu2I sp,sp,%d,smi,smbi\n", framesize); saved = maxargoffset; /space needed for outgoing arguments
int main(int argc, char **argv) { Dwarf_Off off, lastoff; Dwarf *dw; size_t hdr_size; int cufd, error; argv0 = argv[0]; if (argc < 3) usage(); structname = argv[1]; binary = argv[2]; elf_version(EV_CURRENT); cufd = open(binary, O_RDONLY); if (cufd == -1) err(EX_USAGE, "open"); dw = dwarf_begin(cufd, DWARF_C_READ); if (dw == NULL) { error = dwarf_errno(); if (error == DWARF_E_NO_REGFILE) errx(EX_USAGE, "%s: Not a regular file", binary); dwarf_err_errno(EX_DATAERR, error, "dwarf_begin"); } get_elf_pointer_size(dw); /* XXX worry about .debug_types sections later. */ lastoff = off = 0; while (dwarf_nextcu(dw, off, &off, &hdr_size, NULL, NULL, NULL) == 0) { Dwarf_Die cu_die, die; int x; if (dwarf_offdie(dw, lastoff + hdr_size, &cu_die) == NULL) continue; lastoff = off; /* * A CU may be empty because e.g. an empty (or fully #if0'd) * file is compiled. */ if (dwarf_child(&cu_die, &die)) continue; /* Loop through all DIEs in the CU. */ do { if (isstruct(dwarf_tag(&die)) && dwarf_haschildren(&die) && dwarf_diename(&die) && strcmp(dwarf_diename(&die), structname) == 0) { structprobe(dw, &die); goto out; } } while ((x = dwarf_siblingof(&die, &die)) == 0); if (x == -1) dwarf_err(EX_DATAERR, "dwarf_siblingof"); } out: if (dwarf_end(dw)) dwarf_err(EX_SOFTWARE, "dwarf_end"); return (EX_OK); }
static void structprobe(Dwarf *dw, Dwarf_Die *structdie) { Dwarf_Die memdie; Dwarf_Word lastoff = 0, structsize; unsigned cline, members, nholes; size_t memsz, holesz; int x; (void)dw; cline = members = nholes = 0; memsz = holesz = 0; printf("struct %s {\n", dwarf_diename(structdie)); if (dwarf_aggregate_size(structdie, &structsize) == -1) dwarf_err(EX_DATAERR, "dwarf_aggregate_size"); if (dwarf_child(structdie, &memdie)) { printf("XXX ???\n"); exit(EX_DATAERR); } do { Dwarf_Attribute type_attr, base_type_attr; Dwarf_Die type_die, base_type_die; char type_name[128], mem_name[128], ptr_suffix[32] = { '\0' }; const char *type_tag = ""; const char *type = NULL; unsigned type_ptrlevel = 0; Dwarf_Word msize, off; if (dwarf_tag(&memdie) != DW_TAG_member) continue; members++; /* * TODO: Handle bitfield members. DW_AT_bit_offset, * DW_AT_bit_size; */ /* Chase down the type die of this member */ get_dwarf_attr(&memdie, DW_AT_type, &type_attr, &type_die); /* Member offset ... */ if (get_member_offset(&memdie, &off) == -1) dwarf_err(EX_DATAERR, "%s", dwarf_diename(&memdie)); /* Member size. */ if (get_member_size(&type_die, &msize) == -1) dwarf_err(EX_DATAERR, "get_member_size"); /* Format name; 'struct foo', 'enum bar', 'char **', etc. */ if (isstruct(dwarf_tag(&type_die))) { type_tag = "struct "; type = dwarf_diename(&type_die); } else if (dwarf_tag(&type_die) == DW_TAG_enumeration_type) { type_tag = "enum "; type = dwarf_diename(&type_die); } else if (dwarf_tag(&type_die) == DW_TAG_pointer_type) { unsigned i; do { if (dwarf_tag(&type_die) == DW_TAG_pointer_type) type_ptrlevel++; else if (isstruct(dwarf_tag(&type_die))) type_tag = "struct "; else if (dwarf_tag(&type_die) == DW_TAG_enumeration_type) type_tag = "enum "; else printf("!!! XXX ignored pointer qualifier TAG %#x\n", dwarf_tag(&type_die)); /* * Pointers to basic types still need some * work. Clang doesn't emit an AT_TYPE for * 'void*,' for example. */ if (!dwarf_hasattr(&type_die, DW_AT_type)) break; get_dwarf_attr(&type_die, DW_AT_type, &base_type_attr, &base_type_die); type_die = base_type_die; type_attr = base_type_attr; } while (dwarf_tag(&type_die) != DW_TAG_base_type); type = dwarf_diename(&type_die); if (type_ptrlevel > sizeof(ptr_suffix) - 2) type_ptrlevel = sizeof(ptr_suffix) - 2; ptr_suffix[0] = ' '; for (i = 1; i <= type_ptrlevel; i++) ptr_suffix[i] = '*'; ptr_suffix[i] = '\0'; } else type = dwarf_diename(&type_die); if (type == NULL) type = "<anonymous>"; snprintf(type_name, sizeof(type_name), "%s%s%s", type_tag, type, ptr_suffix); if (off != lastoff) { printf("\n\t/* XXX %ld bytes hole, try to pack */\n\n", off - lastoff); nholes++; holesz += (off - lastoff); } snprintf(mem_name, sizeof(mem_name), "%s;", dwarf_diename(&memdie)); printf("\t%-27s%-21s /* %5ld %5ld */\n", type_name, mem_name, (long)off, (long)msize); memsz += msize; lastoff = off + msize; if (lastoff / cachelinesize > cline) { int ago = lastoff % cachelinesize; cline = lastoff / cachelinesize; if (ago) printf("\t/* --- cacheline %u boundary (%ld " "bytes) was %d bytes ago --- */\n", cline, (long)cline * cachelinesize, ago); else printf("\t/* --- cacheline %u boundary (%ld " "bytes) --- */\n", cline, (long)cline * cachelinesize); } } while ((x = dwarf_siblingof(&memdie, &memdie)) == 0); if (x == -1) dwarf_err(EX_DATAERR, "dwarf_siblingof"); printf("\n\t/* size: %lu, cachelines: %u, members: %u */\n", structsize, cline + 1, members); printf("\t/* sum members: %zu, holes: %u, sum holes: %zu */\n", memsz, nholes, holesz); printf("\t/* last cacheline: %lu bytes */\n", lastoff % cachelinesize); printf("};\n"); }
static struct vector *decls(declfun_p * dcl) { struct vector *v = vec_new(); node_t *basety; int sclass, fspec; int level = SCOPE; int follow[] = {STATIC, INT, CONST, IF, '}', 0}; basety = specifiers(&sclass, &fspec); if (token->id == ID || token->id == '*' || token->id == '(') { struct token *id = NULL; node_t *ty = NULL; int params = 0; // for functioness // declarator if (level == GLOBAL) declarator(&ty, &id, ¶ms); else declarator(&ty, &id, NULL); attach_type(&ty, basety); if (level == GLOBAL && params) { if (first_funcdef(ty)) { vec_push(v, funcdef(id, ty, sclass, fspec)); return v; } else { exit_params(); } } for (;;) { if (id) { int kind; if (dcl == globaldecl) kind = GLOBAL; else if (dcl == paramdecl) kind = PARAM; else kind = LOCAL; node_t *decl = make_decl(id, ty, sclass, fspec, dcl); if (token->id == '=') decl_initializer(decl, sclass, kind); ensure_decl(decl, sclass, kind); vec_push(v, decl); } if (token->id != ',') break; expect(','); id = NULL; ty = NULL; // declarator declarator(&ty, &id, NULL); attach_type(&ty, basety); } } else if (isenum(basety) || isstruct(basety) || isunion(basety)) { // struct/union/enum int node_id; node_t *decl; if (isstruct(basety)) node_id = STRUCT_DECL; else if (isunion(basety)) node_id = UNION_DECL; else node_id = ENUM_DECL; decl = ast_decl(node_id); DECL_SYM(decl) = TYPE_TSYM(basety); vec_push(v, decl); } else { error("invalid token '%s' in declaration", token->name); } match(';', follow); return v; }