Info & Block::putSymsInScope(const symbol::Symbol & sym, Block * block, Info & info) { // We put the sym (which is defined in block) in this block and pull all its companions too. Info & i = addSym(sym, info); Data * data = i.data; // emplace called the Info's copy ctor so a new Data has been allocated dm->registerData(data);//, __LINE__, __FILE__); // We put all the shared syms in this scope if (!data->hasOneOwner()) { for (const auto & _sym : data->sharedSyms) { if (sym != _sym) { Info & _i = block->symMap.find(_sym)->second; Data * old = _i.data; // we set _i.data to nullptr to avoid the data copy when cloning _i _i.data = nullptr; addSym(_sym, _i).data = data; _i.data = old; } } } return i; }
Info & Block::putAndClear(const symbol::Symbol & sym, ast::Exp * exp) { tools::SymbolMap<Info>::iterator it; Block * block = getDefBlock(sym, it, false); if (block) { Info & info = it->second; if (block == this) { if (info.data->hasOneOwner()) { info.cleared = true; info.local = Info::Local::INFO_TRUE; return info; } else { info.data->rem(sym); info.data = nullptr; info.cleared = true; info.local = Info::Local::INFO_TRUE; return info; } } else { if (info.data->hasOneOwner()) { Data * old = info.data; info.data = nullptr; Info & i = addSym(sym, info); info.data = old; i.cleared = true; i.local = Info::Local::INFO_TRUE; return i; } else { Info & i = putSymsInScope(sym, block, info); i.data->rem(sym); i.data = nullptr; i.cleared = true; i.local = Info::Local::INFO_TRUE; return i; } } } else { Info & i = addSym(sym, nullptr); i.local = Info::Local::INFO_TRUE; return i; } }
Info & Block::setDefaultData(const symbol::Symbol & sym) { Info & i = addSym(sym, new Data(false, sym)); i.local = Info::Local::INFO_FALSE; i.type = DataManager::getSymInScilabContext(getGVN(), sym, i.exists); addGlobal(sym); dm->registerData(i.data);//, __LINE__, __FILE__); return i; }
/*-----------------------------------------------------------------*/ void deallocParms (value * val) { value *lval; for (lval = val; lval; lval = lval->next) { /* unmark is myparm */ lval->sym->ismyparm = 0; /* delete it from the symbol table */ deleteSym (SymbolTab, lval->sym, lval->sym->name); if (!lval->sym->isref) { lval->sym->allocreq = 0; werror (W_NO_REFERENCE, currFunc ? currFunc->name : "(unknown)", "function argument", lval->sym->name); } /* move the rname if any to the name for both val & sym */ /* and leave a copy of it in the symbol table */ if (lval->sym->rname[0]) { char buffer[SDCC_NAME_MAX]; symbol * argsym = lval->sym; strncpyz (buffer, lval->sym->rname, sizeof(buffer)); lval->sym = copySymbol (lval->sym); strncpyz (lval->sym->rname, buffer, sizeof(lval->sym->rname)); strncpyz (lval->sym->name, buffer, sizeof(lval->sym->name)); /* need to keep the original name for inlining to work */ /*strncpyz (lval->name, buffer, sizeof(lval->name)); */ addSym (SymbolTab, lval->sym, lval->sym->name, lval->sym->level, lval->sym->block, 1); lval->sym->_isparm = 1; if (!isinSet (operKeyReset, lval->sym)) { addSet(&operKeyReset, lval->sym); } /* restore the original symbol */ lval->sym = argsym; } } return; }
/*-----------------------------------------------------------------*/ int allocVariables (symbol * symChain) { symbol *sym; symbol *csym; int stack = 0; int saveLevel = 0; /* go thru the symbol chain */ for (sym = symChain; sym; sym = sym->next) { /* if this is a typedef then add it */ /* to the typedef table */ if (IS_TYPEDEF (sym->etype)) { /* check if the typedef already exists */ csym = findSym (TypedefTab, NULL, sym->name); if (csym && csym->level == sym->level) werror (E_DUPLICATE_TYPEDEF, sym->name); SPEC_EXTR (sym->etype) = 0; addSym (TypedefTab, sym, sym->name, sym->level, sym->block, 0); continue; /* go to the next one */ } /* make sure it already exists */ csym = findSymWithLevel (SymbolTab, sym); if (!csym || (csym && csym->level != sym->level)) csym = sym; /* check the declaration */ checkDecl (csym, 0); /* if this is a function or a pointer to a */ /* function then do args processing */ if (funcInChain (csym->type)) { processFuncArgs (csym); } /* if this is an extern variable then change */ /* the level to zero temporarily */ if (IS_EXTERN (csym->etype) || IS_FUNC (csym->type)) { saveLevel = csym->level; csym->level = 0; } /* if this is a literal then it is an enumerated */ /* type so need not allocate it space for it */ if (IS_LITERAL (sym->etype)) continue; /* generate the actual declaration */ if (csym->level) { allocLocal (csym); if (csym->onStack) stack += getSize (csym->type); } else allocGlobal (csym); /* restore the level */ if (IS_EXTERN (csym->etype) || IS_FUNC (csym->type)) csym->level = saveLevel; } return stack; }
/* Read the symbols from the object/exe specified by the SegInfo into the tables within the supplied SegInfo. */ static void vg_read_lib_symbols ( SegInfo* si ) { Elf32_Ehdr* ehdr; /* The ELF header */ Elf32_Shdr* shdr; /* The section table */ UChar* sh_strtab; /* The section table's string table */ struct nlist* stab; /* The .stab table */ UChar* stabstr; /* The .stab string table */ Int stab_sz; /* Size in bytes of the .stab table */ Int stabstr_sz; /* Size in bytes of the .stab string table */ Int fd; Int i; Bool ok; Addr oimage; Int n_oimage; struct stat stat_buf; /* for the .stabs reader */ Int curr_filenmoff; Addr curr_fnbaseaddr; Addr range_startAddr; Int range_lineno; oimage = (Addr)NULL; if (VG_(clo_verbosity) > 1) VG_(message)(Vg_UserMsg, "Reading syms from %s", si->filename ); /* mmap the object image aboard, so that we can read symbols and line number info out of it. It will be munmapped immediately thereafter; it is only aboard transiently. */ i = stat(si->filename, &stat_buf); if (i != 0) { vg_symerr("Can't stat .so/.exe (to determine its size)?!"); return; } n_oimage = stat_buf.st_size; fd = VG_(open_read)(si->filename); if (fd == -1) { vg_symerr("Can't open .so/.exe to read symbols?!"); return; } oimage = (Addr)VG_(mmap)( NULL, n_oimage, PROT_READ, MAP_PRIVATE, fd, 0 ); if (oimage == ((Addr)(-1))) { VG_(message)(Vg_UserMsg, "mmap failed on %s", si->filename ); VG_(close)(fd); return; } VG_(close)(fd); /* Ok, the object image is safely in oimage[0 .. n_oimage-1]. Now verify that it is a valid ELF .so or executable image. */ ok = (n_oimage >= sizeof(Elf32_Ehdr)); ehdr = (Elf32_Ehdr*)oimage; if (ok) { ok &= (ehdr->e_ident[EI_MAG0] == 0x7F && ehdr->e_ident[EI_MAG1] == 'E' && ehdr->e_ident[EI_MAG2] == 'L' && ehdr->e_ident[EI_MAG3] == 'F'); ok &= (ehdr->e_ident[EI_CLASS] == ELFCLASS32 && ehdr->e_ident[EI_DATA] == ELFDATA2LSB && ehdr->e_ident[EI_VERSION] == EV_CURRENT); ok &= (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN); ok &= (ehdr->e_machine == EM_386); ok &= (ehdr->e_version == EV_CURRENT); ok &= (ehdr->e_shstrndx != SHN_UNDEF); ok &= (ehdr->e_shoff != 0 && ehdr->e_shnum != 0); } if (!ok) { vg_symerr("Invalid ELF header, or missing stringtab/sectiontab."); VG_(munmap) ( (void*)oimage, n_oimage ); return; } if (VG_(clo_trace_symtab)) VG_(printf)( "shoff = %d, shnum = %d, size = %d, n_vg_oimage = %d\n", ehdr->e_shoff, ehdr->e_shnum, sizeof(Elf32_Shdr), n_oimage ); if (ehdr->e_shoff + ehdr->e_shnum*sizeof(Elf32_Shdr) > n_oimage) { vg_symerr("ELF section header is beyond image end?!"); VG_(munmap) ( (void*)oimage, n_oimage ); return; } shdr = (Elf32_Shdr*)(oimage + ehdr->e_shoff); sh_strtab = (UChar*)(oimage + shdr[ehdr->e_shstrndx].sh_offset); /* try and read the object's symbol table */ { UChar* o_strtab = NULL; Elf32_Sym* o_symtab = NULL; UInt o_strtab_sz = 0; UInt o_symtab_sz = 0; UChar* o_got = NULL; UChar* o_plt = NULL; UInt o_got_sz = 0; UInt o_plt_sz = 0; Bool snaffle_it; Addr sym_addr; /* find the .stabstr and .stab sections */ for (i = 0; i < ehdr->e_shnum; i++) { if (0 == VG_(strcmp)(".symtab",sh_strtab + shdr[i].sh_name)) { o_symtab = (Elf32_Sym*)(oimage + shdr[i].sh_offset); o_symtab_sz = shdr[i].sh_size; vg_assert((o_symtab_sz % sizeof(Elf32_Sym)) == 0); /* check image overrun here */ } if (0 == VG_(strcmp)(".strtab",sh_strtab + shdr[i].sh_name)) { o_strtab = (UChar*)(oimage + shdr[i].sh_offset); o_strtab_sz = shdr[i].sh_size; /* check image overrun here */ } /* find out where the .got and .plt sections will be in the executable image, not in the object image transiently loaded. */ if (0 == VG_(strcmp)(".got",sh_strtab + shdr[i].sh_name)) { o_got = (UChar*)(si->offset + shdr[i].sh_offset); o_got_sz = shdr[i].sh_size; /* check image overrun here */ } if (0 == VG_(strcmp)(".plt",sh_strtab + shdr[i].sh_name)) { o_plt = (UChar*)(si->offset + shdr[i].sh_offset); o_plt_sz = shdr[i].sh_size; /* check image overrun here */ } } if (VG_(clo_trace_symtab)) { if (o_plt) VG_(printf)( "PLT: %p .. %p\n", o_plt, o_plt + o_plt_sz - 1 ); if (o_got) VG_(printf)( "GOT: %p .. %p\n", o_got, o_got + o_got_sz - 1 ); } if (o_strtab == NULL || o_symtab == NULL) { vg_symerr(" object doesn't have a symbol table"); } else { /* Perhaps should start at i = 1; ELF docs suggest that entry 0 always denotes `unknown symbol'. */ for (i = 1; i < o_symtab_sz/sizeof(Elf32_Sym); i++){ # if 0 VG_(printf)("raw symbol: "); switch (ELF32_ST_BIND(o_symtab[i].st_info)) { case STB_LOCAL: VG_(printf)("LOC "); break; case STB_GLOBAL: VG_(printf)("GLO "); break; case STB_WEAK: VG_(printf)("WEA "); break; case STB_LOPROC: VG_(printf)("lop "); break; case STB_HIPROC: VG_(printf)("hip "); break; default: VG_(printf)("??? "); break; } switch (ELF32_ST_TYPE(o_symtab[i].st_info)) { case STT_NOTYPE: VG_(printf)("NOT "); break; case STT_OBJECT: VG_(printf)("OBJ "); break; case STT_FUNC: VG_(printf)("FUN "); break; case STT_SECTION: VG_(printf)("SEC "); break; case STT_FILE: VG_(printf)("FIL "); break; case STT_LOPROC: VG_(printf)("lop "); break; case STT_HIPROC: VG_(printf)("hip "); break; default: VG_(printf)("??? "); break; } VG_(printf)( ": value %p, size %d, name %s\n", si->offset+(UChar*)o_symtab[i].st_value, o_symtab[i].st_size, o_symtab[i].st_name ? ((Char*)o_strtab+o_symtab[i].st_name) : (Char*)"NONAME"); # endif /* Figure out if we're interested in the symbol. Firstly, is it of the right flavour? */ snaffle_it = ( (ELF32_ST_BIND(o_symtab[i].st_info) == STB_GLOBAL || ELF32_ST_BIND(o_symtab[i].st_info) == STB_LOCAL /* || ELF32_ST_BIND(o_symtab[i].st_info) == STB_WEAK */) && (ELF32_ST_TYPE(o_symtab[i].st_info) == STT_FUNC /*|| ELF32_ST_TYPE(o_symtab[i].st_info) == STT_OBJECT*/) ); /* Secondly, if it's apparently in a GOT or PLT, it's really a reference to a symbol defined elsewhere, so ignore it. */ sym_addr = si->offset + (UInt)o_symtab[i].st_value; if (o_got != NULL && sym_addr >= (Addr)o_got && sym_addr < (Addr)(o_got+o_got_sz)) { snaffle_it = False; if (VG_(clo_trace_symtab)) { VG_(printf)( "in GOT: %s\n", o_strtab+o_symtab[i].st_name); } } if (o_plt != NULL && sym_addr >= (Addr)o_plt && sym_addr < (Addr)(o_plt+o_plt_sz)) { snaffle_it = False; if (VG_(clo_trace_symtab)) { VG_(printf)( "in PLT: %s\n", o_strtab+o_symtab[i].st_name); } } /* Don't bother if nameless, or zero-sized. */ if (snaffle_it && (o_symtab[i].st_name == (Elf32_Word)NULL || /* VG_(strlen)(o_strtab+o_symtab[i].st_name) == 0 */ /* equivalent but cheaper ... */ * ((UChar*)(o_strtab+o_symtab[i].st_name)) == 0 || o_symtab[i].st_size == 0)) { snaffle_it = False; if (VG_(clo_trace_symtab)) { VG_(printf)( "size=0: %s\n", o_strtab+o_symtab[i].st_name); } } # if 0 /* Avoid _dl_ junk. (Why?) */ /* 01-02-24: disabled until I find out if it really helps. */ if (snaffle_it && (VG_(strncmp)("_dl_", o_strtab+o_symtab[i].st_name, 4) == 0 || VG_(strncmp)("_r_debug", o_strtab+o_symtab[i].st_name, 8) == 0)) { snaffle_it = False; if (VG_(clo_trace_symtab)) { VG_(printf)( "_dl_ junk: %s\n", o_strtab+o_symtab[i].st_name); } } # endif /* This seems to significantly reduce the number of junk symbols, and particularly reduces the number of overlapping address ranges. Don't ask me why ... */ if (snaffle_it && (Int)o_symtab[i].st_value == 0) { snaffle_it = False; if (VG_(clo_trace_symtab)) { VG_(printf)( "valu=0: %s\n", o_strtab+o_symtab[i].st_name); } } /* If no part of the symbol falls within the mapped range, ignore it. */ if (sym_addr+o_symtab[i].st_size <= si->start || sym_addr >= si->start+si->size) { snaffle_it = False; } if (snaffle_it) { /* it's an interesting symbol; record ("snaffle") it. */ RiSym sym; Char* t0 = o_symtab[i].st_name ? (Char*)(o_strtab+o_symtab[i].st_name) : (Char*)"NONAME"; Int nmoff = addStr ( si, t0 ); vg_assert(nmoff >= 0 /* && 0==VG_(strcmp)(t0,&vg_strtab[nmoff]) */ ); vg_assert( (Int)o_symtab[i].st_value >= 0); /* VG_(printf)("%p + %d: %s\n", si->addr, (Int)o_symtab[i].st_value, t0 ); */ sym.addr = sym_addr; sym.size = o_symtab[i].st_size; sym.nmoff = nmoff; addSym ( si, &sym ); } } } } /* Reading of the "stabs" debug format information, if any. */ stabstr = NULL; stab = NULL; stabstr_sz = 0; stab_sz = 0; /* find the .stabstr and .stab sections */ for (i = 0; i < ehdr->e_shnum; i++) { if (0 == VG_(strcmp)(".stab",sh_strtab + shdr[i].sh_name)) { stab = (struct nlist *)(oimage + shdr[i].sh_offset); stab_sz = shdr[i].sh_size; } if (0 == VG_(strcmp)(".stabstr",sh_strtab + shdr[i].sh_name)) { stabstr = (UChar*)(oimage + shdr[i].sh_offset); stabstr_sz = shdr[i].sh_size; } } if (stab == NULL || stabstr == NULL) { vg_symerr(" object doesn't have any debug info"); VG_(munmap) ( (void*)oimage, n_oimage ); return; } if ( stab_sz + (UChar*)stab > n_oimage + (UChar*)oimage || stabstr_sz + (UChar*)stabstr > n_oimage + (UChar*)oimage ) { vg_symerr(" ELF debug data is beyond image end?!"); VG_(munmap) ( (void*)oimage, n_oimage ); return; } /* Ok. It all looks plausible. Go on and read debug data. stab kinds: 100 N_SO a source file name 68 N_SLINE a source line number 36 N_FUN ? start of a function In this loop, we maintain a current file name, updated as N_SOs appear, and a current function base address, updated as N_FUNs appear. Based on that, address ranges for N_SLINEs are calculated, and stuffed into the line info table. N_SLINE indicates the start of a source line. Functions are delimited by N_FUNS, at the start with a non-empty string and at the end with an empty string. The latter facilitates detecting where to close the last N_SLINE for a function. */ curr_filenmoff = addStr(si,"???"); curr_fnbaseaddr = (Addr)NULL; range_startAddr = 0; range_lineno = 0; for (i = 0; i < stab_sz/(int)sizeof(struct nlist); i++) { # if 0 VG_(printf) ( " %2d ", i ); VG_(printf) ( "type=0x%x othr=%d desc=%d value=0x%x strx=%d %s", stab[i].n_type, stab[i].n_other, stab[i].n_desc, (int)stab[i].n_value, (int)stab[i].n_un.n_strx, stabstr + stab[i].n_un.n_strx ); VG_(printf)("\n"); # endif switch (stab[i].n_type) { case 68: { /* N_SLINE */ /* flush the current line, if any, and start a new one */ Addr range_endAddr = curr_fnbaseaddr + (UInt)stab[i].n_value - 1; if (range_startAddr != 0) { addLineInfo ( si, curr_filenmoff, range_startAddr, range_endAddr, range_lineno ); } range_startAddr = range_endAddr + 1; range_lineno = stab[i].n_desc; break; } case 36: { /* N_FUN */ if ('\0' == * (stabstr + stab[i].n_un.n_strx) ) { /* N_FUN with no name -- indicates the end of a fn. Flush the current line, if any, but don't start a new one. */ Addr range_endAddr = curr_fnbaseaddr + (UInt)stab[i].n_value - 1; if (range_startAddr != 0) { addLineInfo ( si, curr_filenmoff, range_startAddr, range_endAddr, range_lineno ); } range_startAddr = 0; } else { /* N_FUN with a name -- indicates the start of a fn. */ curr_fnbaseaddr = si->offset + (Addr)stab[i].n_value; range_startAddr = curr_fnbaseaddr; } break; } case 100: /* N_SO */ case 132: /* N_SOL */ /* seems to give lots of locations in header files */ /* case 130: */ /* BINCL */ { UChar* nm = stabstr + stab[i].n_un.n_strx; UInt len = VG_(strlen)(nm); if (len > 0 && nm[len-1] != '/') curr_filenmoff = addStr ( si, nm ); else if (len == 0) curr_filenmoff = addStr ( si, "?1\0" ); break; } # if 0 case 162: /* EINCL */ curr_filenmoff = addStr ( si, "?2\0" ); break; # endif default: break; } } /* for (i = 0; i < stab_sz/(int)sizeof(struct nlist); i++) */ /* Last, but not least, heave the oimage back overboard. */ VG_(munmap) ( (void*)oimage, n_oimage ); }