/* * Gets a symbol scope table record. * Returns pointer to a hll_ssr_common structure on success. */ void *VMSsRecord( imp_image_handle *ii, hll_dir_entry *hde, unsigned_32 rec_off, unsigned_32 *next_rec, unsigned_16 *sizep ) { unsigned_16 size = 0; unsigned_8 *p = NULL; if( rec_off + 2 <= hde->cb) { p = VMBlock( ii, hde->lfo + rec_off, 2 ); if( p != NULL ) { size = *p; if( size & 0x80 ) { size = (size & 0x7f) << 8; size |= p[1]; rec_off++; } rec_off++; if( rec_off + size <= hde->cb ) { p = VMBlock( ii, hde->lfo + rec_off, size ); } } } if( sizep ) { *sizep = size; } if( next_rec ) { *next_rec = rec_off + size; } return( p ); }
search_result DIPENTRY DIPImpLineCue( imp_image_handle *ii, imp_mod_handle im, cue_file_id file, unsigned long line, unsigned column, imp_cue_handle *ic ) { cv_directory_entry *cde; cv_sst_src_module_header *hdr; cv_sst_src_module_file_table *fp; cv_sst_src_module_line_number *lp; unsigned_32 *line_off; unsigned num_segs; unsigned seg_idx; unsigned long best_line; virt_mem line_base; virt_mem num_base; unsigned num_pairs; unsigned pair; unsigned_16 *line_number; column = column; cde = FindDirEntry( ii, im, sstSrcModule ); if( cde == NULL ) return( SR_NONE ); if( file == 0 ) { hdr = VMBlock( ii, cde->lfo, sizeof( *hdr ) ); if( hdr == NULL ) return( SR_NONE ); file = hdr->baseSrcFile[0] + cde->lfo; } ic->im = im; ic->file = file; fp = VMBlock( ii, file, sizeof( *fp ) ); if( fp == NULL ) return( SR_NONE ); num_segs = fp->cSeg; fp = VMBlock( ii, file, sizeof( *fp ) + num_segs * sizeof( unsigned_32 ) ); if( fp == NULL ) return( SR_NONE ); /* make a copy of the line/offset table so that we don't have to worry about the VM system throwing it out */ line_off = __alloca( num_segs * sizeof( unsigned_32 ) ); memcpy( line_off, &fp->baseSrcLn[0], num_segs * sizeof( unsigned_32 ) ); best_line = -1UL; for( seg_idx = 0; seg_idx < num_segs; ++seg_idx ) { line_base = line_off[seg_idx] + cde->lfo; lp = VMBlock( ii, line_base, sizeof( *lp ) ); if( lp == NULL ) return( SR_NONE ); num_pairs = lp->cPair; num_base = line_base + offsetof( cv_sst_src_module_line_number, offset ) + (unsigned long)num_pairs * sizeof( unsigned_32 ); for( pair = 0; pair < num_pairs; ++pair ) { line_number = VMBlock( ii, num_base, sizeof( *line_number ) ); if( *line_number >= line && *line_number < best_line ) { best_line = *line_number; ic->line = line_base; ic->pair = pair; if( best_line == line ) return( SR_EXACT ); } num_base += sizeof( *line_number ); } } if( best_line == -1UL ) return( SR_NONE ); return( SR_CLOSEST ); }
search_result SearchFile( imp_image_handle *ii, address addr, imp_cue_handle *ic, virt_mem file_base, cv_directory_entry *cde, addr_off *best_offset) { cv_sst_src_module_file_table *fp; cv_sst_src_module_line_number *lp; virt_mem line_base; off_range *ranges; unsigned_32 *lines; unsigned num_segs; unsigned seg_idx; address curr_addr; unsigned pair; fp = VMBlock( ii, file_base, sizeof( *fp ) ); if( fp == NULL ) return( SR_NONE ); num_segs = fp->cSeg; fp = VMBlock( ii, file_base, sizeof( *fp ) + num_segs * (sizeof( unsigned_32 ) + sizeof( off_range ) ) ); if( fp == NULL ) return( SR_NONE ); ranges = __alloca( num_segs * sizeof( *ranges ) ); lines = __alloca( num_segs * sizeof( *lines ) ); memcpy( lines, &fp->baseSrcLn[0], num_segs * sizeof( *lines ) ); memcpy( ranges, &fp->baseSrcLn[num_segs], num_segs * sizeof( *ranges ) ); for( seg_idx = 0; seg_idx < num_segs; ++seg_idx ) { line_base = lines[seg_idx] + cde->lfo; lp = VMBlock( ii, line_base, sizeof( *lp ) ); if( lp == NULL ) return( SR_NONE ); curr_addr.mach.segment = lp->Seg; curr_addr.mach.offset = 0; MapLogical( ii, &curr_addr ); if( DCSameAddrSpace( curr_addr, addr ) != DS_OK ) continue; if( (ranges[seg_idx].start != 0 || ranges[seg_idx].end != 0) && (addr.mach.offset < ranges[seg_idx].start + curr_addr.mach.offset /* The next condition is commented out. Digital Mars tools are known to * emit buggy CV4 data where the upper range does not cover all code, * causing us to fail finding last addresses within a module. */ /*|| addr.mach.offset > ranges[seg_idx].end + curr_addr.mach.offset */ ) ) { continue; } pair = SearchOffsets( ii, line_base + offsetof( cv_sst_src_module_line_number, offset[0] ), lp->cPair, addr.mach.offset, best_offset, curr_addr.mach.offset ); if( pair != NO_IDX ) { ic->file = file_base; ic->line = line_base; ic->pair = pair; if( *best_offset == addr.mach.offset ) return( SR_EXACT ); } } /* We abuse the SR_FAIL return code to really mean SR_CONTINUE (ie. continue * searching other files). A SR_CONTINUE code is not defined because it does * not make sense as a return value for DIPImpAddrCue() */ return( SR_FAIL ); }
search_result DIPENTRY DIPImpAddrCue( imp_image_handle *ii, imp_mod_handle im, address addr, imp_cue_handle *ic ) { cv_directory_entry *cde; cv_sst_src_module_header *hdr; unsigned_32 *files; virt_mem file_base; unsigned num_files; unsigned file_idx; addr_off best_offset; unsigned file_tab_size; search_result rc; cde = FindDirEntry( ii, im, sstSrcModule ); if( cde == NULL ) return( SR_NONE ); hdr = VMBlock( ii, cde->lfo, sizeof( *hdr ) ); if( hdr == NULL ) return( SR_NONE ); ic->im = im; num_files = hdr->cFile; file_tab_size = num_files * sizeof( unsigned_32 ); hdr = VMBlock( ii, cde->lfo, sizeof( *hdr ) + file_tab_size ); files = __alloca( file_tab_size ); memcpy( files, &hdr->baseSrcFile[0], file_tab_size ); best_offset = (addr_off)-1UL; for( file_idx = 0; file_idx < num_files; ++file_idx ) { file_base = files[file_idx] + cde->lfo; rc = SearchFile( ii, addr, ic, file_base, cde, &best_offset ); if( rc != SR_FAIL ) return( rc ); /* see comment in SearchFile above */ } if( best_offset == (addr_off)-1UL ) return( SR_NONE ); return( SR_CLOSEST ); }
static dip_status AdjBackward( imp_image_handle *ii, unsigned long bias, imp_cue_handle *ic ) { cv_sst_src_module_line_number *lp; cv_sst_src_module_file_table *fp; dip_status ds; unsigned i; ds = DS_OK; ic->pair--; lp = VMBlock( ii, ic->line, sizeof( *lp ) ); if( lp == NULL ) return( DS_ERR|DS_FAIL ); for( ;; ) { /* if ic->pair went negative, the following compare will fail because of unsigned comparison */ if( ic->pair < lp->cPair ) return( ds ); fp = VMBlock( ii, ic->file, sizeof( *fp ) ); if( fp == NULL ) return( DS_ERR|DS_FAIL ); fp = VMBlock( ii, ic->file, sizeof( *fp ) + fp->cSeg * sizeof( unsigned_32 ) ); if( fp == NULL ) return( DS_ERR|DS_FAIL ); i = 0; for( ;; ) { if( (fp->baseSrcLn[i] + bias) == ic->line ) break; ++i; } if( --i >= fp->cSeg ) { i = fp->cSeg - 1; ds = DS_WRAPPED; } ic->line = fp->baseSrcLn[i] + bias; lp = VMBlock( ii, ic->line, sizeof( *lp ) ); if( lp == NULL ) return( DS_ERR|DS_FAIL ); ic->pair = lp->cPair - 1; } }
static dip_status AdjForward( imp_image_handle *ii, unsigned long bias, imp_cue_handle *ic ) { cv_sst_src_module_line_number *lp; cv_sst_src_module_file_table *fp; dip_status ds; unsigned i; ds = DS_OK; ic->pair++; for( ;; ) { lp = VMBlock( ii, ic->line, sizeof( *lp ) ); if( lp == NULL ) return( DS_ERR|DS_FAIL ); if( ic->pair < lp->cPair ) return( ds ); fp = VMBlock( ii, ic->file, sizeof( *fp ) ); if( fp == NULL ) return( DS_ERR|DS_FAIL ); fp = VMBlock( ii, ic->file, sizeof( *fp ) + fp->cSeg * sizeof( unsigned_32 ) ); if( fp == NULL ) return( DS_ERR|DS_FAIL ); i = 0; for( ;; ) { if( (fp->baseSrcLn[i] + bias) == ic->line ) break; ++i; } if( ++i >= fp->cSeg ) { i = 0; ds = DS_WRAPPED; } ic->line = fp->baseSrcLn[i] + bias; ic->pair = 0; } }
void *VMRecord( imp_image_handle *iih, virt_mem rec ) { s_common *p; p = VMBlock( iih, rec, sizeof( *p ) ); if( p != NULL ) { p = VMBlock( iih, rec, p->length + sizeof( p->length ) ); } return( p ); }
unsigned SearchOffsets( imp_image_handle *ii, virt_mem base, unsigned num_off, addr_off want_off, addr_off *best_off, addr_off adj_off ) { int lo_idx; int hi_idx; int idx; addr_off lo_off; addr_off hi_off; addr_off off; addr_off *offp; #define VMADDR( i ) (base + (i)*sizeof(addr_off)) lo_idx = 0; hi_idx = num_off - 1; offp = VMBlock( ii, VMADDR( lo_idx ), sizeof( *offp ) ); if( offp == NULL ) return( NO_IDX ); lo_off = *offp + adj_off; offp = VMBlock( ii, VMADDR( hi_idx ), sizeof( *offp ) ); if( offp == NULL ) return( NO_IDX ); hi_off = *offp + adj_off; while( lo_idx <= hi_idx ) { idx = (lo_idx + hi_idx ) >> 1; offp = VMBlock( ii, VMADDR( idx ), sizeof( *offp ) ); if( offp == NULL ) return( NO_IDX ); off = *offp + adj_off; if( want_off < off ) { hi_idx = idx - 1; offp = VMBlock( ii, VMADDR( hi_idx ), sizeof( *offp ) ); if( offp == NULL ) return( NO_IDX ); hi_off = *offp + adj_off; } else if( want_off > off ) { lo_idx = idx + 1; offp = VMBlock( ii, VMADDR( lo_idx ), sizeof( *offp ) ); if( offp == NULL ) return( NO_IDX ); lo_off = *offp + adj_off; } else { hi_idx = idx; hi_off = off; break; } } if( hi_idx < 0 ) return( NO_IDX ); if( hi_off > *best_off ) return( NO_IDX ); *best_off = hi_off; return( hi_idx ); }
/* * Get a block within a section. */ void *VMSsBlock( imp_image_handle *ii, hll_dir_entry *hde, unsigned_32 start, size_t len ) { if( start < hde->cb && start + len <= hde->cb ) { return( VMBlock( ii, hde->lfo + start, len ) ); } return( NULL ); }
unsigned DIGENTRY DIPImpModName( imp_image_handle *ii, imp_mod_handle im, char *buff, unsigned buff_size ) { cv_directory_entry *cde; cv_sst_module *mp; const char *name; const char *start; const char *end; unsigned len; if( im == IMH_GBL ) { return( NameCopy( buff, GBL_NAME, buff_size, sizeof( GBL_NAME ) - 1 ) ); } cde = FindDirEntry( ii, im, sstModule ); mp = VMBlock( ii, cde->lfo, cde->cb ); if( mp == NULL ) return( 0 ); name = (char *)&mp->SegInfo[mp->cSeg]; len = *(unsigned_8 *)name; ++name; start = name; end = name + len; for( ; len != 0; ) { if( IS_PATH_CHAR( *name ) ) { start = name + 1; end = name + len; } if( *name == EXT_CHAR ) end = name; ++name; --len; } return( NameCopy( buff, start, buff_size, end - start ) ); }
static walk_result FindAddr( imp_image_handle *ii, cv_directory_entry *cde, void *d ) { struct find_mod *md = d; address *a; address code; cv_sst_module *mp; cv_seginfo *sp; int left; if( cde->subsection != sstModule ) return( WR_CONTINUE ); a = md->d; mp = VMBlock( ii, cde->lfo, cde->cb ); if( mp == NULL ) return( WR_CONTINUE ); if( mp->ovlNumber != a->sect_id ) return( WR_CONTINUE ); sp = &mp->SegInfo[0]; left = mp->cSeg; for( ;; ) { if( left <= 0 ) return( WR_CONTINUE ); code.mach.segment = sp->Seg; code.mach.offset = sp->offset; MapLogical( ii, &code ); if( code.mach.segment == a->mach.segment && code.mach.offset <= a->mach.offset && (code.mach.offset+sp->cbSeg) > a->mach.offset ) { md->im = cde->iMod; return( WR_STOP ); } ++sp; --left; } }
unsigned long DIPENTRY DIPImpCueLine( imp_image_handle *ii, imp_cue_handle *ic ) { cv_sst_src_module_line_number *lp; unsigned long offset; unsigned_16 *num; lp = VMBlock( ii, ic->line, sizeof( *lp ) ); if( lp == NULL ) return( 0 ); if( lp->cPair == 0 ) return( 0 ); offset = offsetof( cv_sst_src_module_line_number, offset ) + (unsigned long)lp->cPair * sizeof( unsigned_32 ) + ic->pair * sizeof( unsigned_16 ); num = VMBlock( ii, ic->line + offset, sizeof( unsigned_16 ) ); if( num == NULL ) return( 0 ); return( *num ); }
/* * Get a 32-bit value. */ bool VMGetU32( imp_image_handle *ii, virt_mem start, unsigned_32 *valp ) { unsigned_32 *ptr = VMBlock( ii, start, sizeof(*valp) ); if( ptr ) { *valp = *ptr; return( TRUE ); } return( FALSE ); }
/* * Get a 32-bit value. */ bool VMSsGetU32( imp_image_handle *ii, hll_dir_entry *hde, unsigned_32 start, unsigned_32 *valp ) { if( start <= hde->cb - sizeof(*valp) ) { unsigned_32 *ptr = VMBlock( ii, hde->lfo + start, sizeof(*valp) ); if( ptr ) { *valp = *ptr; return( TRUE ); } } return( FALSE ); }
address DIPENTRY DIPImpCueAddr( imp_image_handle *ii, imp_cue_handle *ic ) { cv_sst_src_module_line_number *lp; address addr; unsigned long offset; unsigned_32 *off_p; lp = VMBlock( ii, ic->line, sizeof( *lp ) ); if( lp == NULL ) return( NilAddr ); if( lp->cPair == 0 ) return( NilAddr ); addr.mach.segment = lp->Seg; offset = offsetof( cv_sst_src_module_line_number, offset ) + (unsigned long)ic->pair * sizeof( unsigned_32 ); off_p = VMBlock( ii, ic->line + offset, sizeof( unsigned_16 ) ); if( off_p == NULL ) return( NilAddr ); addr.mach.offset = *off_p; MapLogical( ii, &addr ); return( addr ); }
static dip_status LoadMapping( imp_image_handle *ii ) { cv_directory_entry *cde; cv_sst_seg_map *map; size_t size; cde = FindDirEntry( ii, IMH_GBL, sstSegMap ); if( cde == NULL ) return( DS_ERR|DS_INFO_INVALID ); map = VMBlock( ii, cde->lfo, cde->cb ); if( map == NULL ) return( DS_ERR|DS_FAIL ); size = map->cSegLog * sizeof( map->segdesc[0] ); ii->mapping = DCAlloc( size ); if( ii->mapping == NULL ) return( DS_ERR|DS_NO_MEM ); map = VMBlock( ii, cde->lfo, cde->cb ); /* malloc might have unloaded */ memcpy( ii->mapping, &map->segdesc[0], size ); ii->map_count = map->cSegLog; return( DS_OK ); }
walk_result DIPENTRY DIPImpWalkFileList( imp_image_handle *ii, imp_mod_handle im, IMP_CUE_WKR *wk, imp_cue_handle *ic, void *d ) { cv_directory_entry *cde; cv_sst_src_module_header *hdr; cv_sst_src_module_file_table *fp; unsigned_32 *file_off; unsigned file_tab_size; unsigned file_tab_count; unsigned i; walk_result wr; if( im == MH_GBL ) return( WR_CONTINUE ); cde = FindDirEntry( ii, im, sstSrcModule ); if( cde == NULL ) return( WR_CONTINUE ); hdr = VMBlock( ii, cde->lfo, sizeof( *hdr ) ); if( hdr == NULL ) return( WR_FAIL ); file_tab_count = hdr->cFile; file_tab_size = file_tab_count * sizeof( unsigned_32 ); hdr = VMBlock( ii, cde->lfo, sizeof( *hdr ) + file_tab_size ); /* Make a copy of the file table offset so that we don't have to worry about the VM system throwing it out. */ file_off = __alloca( file_tab_size ); memcpy( file_off, &hdr->baseSrcFile[0], file_tab_size ); ic->im = im; for( i = 0; i < file_tab_count; ++i ) { ic->pair = 0; ic->file = cde->lfo + file_off[i]; fp = VMBlock( ii, ic->file, sizeof( *fp ) ); if( fp == NULL ) return( WR_FAIL ); ic->line = cde->lfo + fp->baseSrcLn[0]; wr = wk( ii, ic, d ); if( wr != WR_CONTINUE ) return( wr ); } return( WR_CONTINUE ); }
unsigned DIPENTRY DIPImpCueFile( imp_image_handle *ii, imp_cue_handle *ic, char *buff, unsigned max ) { void *p; unsigned_16 name_len; cv_sst_src_module_file_table *fp; virt_mem offset; offset = ic->file; fp = VMBlock( ii, offset, sizeof( *fp ) ); if( fp == 0 ) return( 0 ); offset += offsetof( cv_sst_src_module_file_table, baseSrcLn ) + (fp->cSeg * (sizeof( unsigned_32 ) * 3)); p = VMBlock( ii, offset, sizeof( unsigned_16 ) ); if( p == NULL ) return( 0 ); /* Doc says the length is unsigned_16, cvpack says 8. */ name_len = *(unsigned_8 *)p; p = VMBlock( ii, offset + sizeof( unsigned_8 ), name_len ); if( p == NULL ) return( 0 ); return( NameCopy( buff, p, max, name_len ) ); }
dip_status DIPIMPENTRY( LoadInfo )( dig_fhandle fid, imp_image_handle *ii ) { dip_status ds; unsigned long off; unsigned long size; cv_directory_entry *cde; cv_sst_global_types_header *hdr; memset( ii, 0, sizeof( *ii ) ); ds = FindCV( fid, &off, &size ); if( ds != DS_OK ) return( ds ); ii->sym_fid = fid; ii->bias = off; ds = VMInit( ii, size ); if( ds != DS_OK ) return( ds ); ii->next_image = ImageList; ImageList = ii; ds = LoadDirectory( ii, off + CV_SIG_SIZE ); if( ds != DS_OK ) { DCStatus( ds ); Cleanup( ii ); return( ds ); } ds = LoadMapping( ii ); if( ds != DS_OK ) { DCStatus( ds ); Cleanup( ii ); return( ds ); } cde = FindDirEntry( ii, IMH_GBL, sstGlobalTypes ); if( cde != NULL ) { hdr = VMBlock( ii, cde->lfo, sizeof( *hdr ) ); if( hdr == NULL ) { Cleanup( ii ); return( DS_ERR|DS_FAIL ); } ii->types_base = cde->lfo + offsetof(cv_sst_global_types_header, offType ) + hdr->cType * sizeof( hdr->offType[0] ); } ds = SetMADType( ii ); if( ds != DS_OK ) { DCStatus( ds ); Cleanup( ii ); return( ds ); } return( DS_OK ); }
/* * Gets a symbol scope table record. * Returns pointer to a hll_ssr_common structure on success. */ void *VMRecord( imp_image_handle *ii, virt_mem rec_off, virt_mem *next_rec, unsigned_16 *sizep ) { unsigned_16 size = 0; unsigned_8 *p; p = VMBlock( ii, rec_off, 2 ); if( p != NULL ) { size = *p; if( size & 0x80 ) { size = (size & 0x7f) << 8; size |= p[1]; rec_off++; } rec_off++; p = VMBlock( ii, rec_off, size ); } if( sizep ) { *sizep = size; } if( next_rec ) { *next_rec = rec_off + size; } return( p ); }
address DIGENTRY DIPImpModAddr( imp_image_handle *ii, imp_mod_handle im ) { cv_sst_module *mp; cv_directory_entry *cde; address addr; cde = FindDirEntry( ii, im, sstModule ); if( cde == NULL ) return( NilAddr ); mp = VMBlock( ii, cde->lfo, cde->cb ); if( mp == NULL ) return( NilAddr ); if( mp->cSeg == 0 ) return( NilAddr ); addr.mach.segment = mp->SegInfo[0].Seg; addr.mach.offset = mp->SegInfo[0].offset; MapLogical( ii, &addr ); return( addr ); }