static unsigned BRead( dig_fhandle h, void *b, unsigned s ) { unsigned got; unsigned want; if( s > sizeof( Buff.data ) ) { Buff.fpos = DCSeek( h, Buff.fpos + Buff.off - Buff.len, DIG_ORG ); Buff.len = 0; Buff.off = 0; if( Buff.fpos == -1UL ) return( 0 ); got = DCRead( h, b, s ); Buff.fpos += got; return( got ); } want = s; got = Buff.len - Buff.off; if( got > want ) got = want; memcpy( b, &Buff.data[Buff.off], got ); Buff.off += got; want -= got; if( want > 0 ) { Buff.len = DCRead( h, &Buff.data[0], sizeof( Buff.data ) ); if( Buff.len == (unsigned)-1 ) { Buff.fpos = -1UL; Buff.off = 0; Buff.len = 0; return( (unsigned)-1 ); } Buff.fpos += Buff.len; b = (unsigned_8 *)b + got; memcpy( b, &Buff.data[0], want ); Buff.off = want; } return( s ); }
static dip_status LoadDirectory( imp_image_handle *ii, unsigned long off ) { unsigned_32 directory; cv_subsection_directory dir_header; unsigned block_count; unsigned i; unsigned left; size_t block_size; unsigned num; if( DCSeek( ii->sym_fid, off, DIG_ORG ) != off ) { return( DS_ERR|DS_FSEEK_FAILED ); } if( DCRead( ii->sym_fid, &directory, sizeof( directory ) ) != sizeof( directory ) ) { return( DS_ERR|DS_FREAD_FAILED ); } if( DCSeek( ii->sym_fid, ii->bias + directory, DIG_ORG ) != (ii->bias + directory) ) { return( DS_ERR|DS_FSEEK_FAILED ); } if( DCRead( ii->sym_fid, &dir_header, sizeof( dir_header ) ) != sizeof( dir_header ) ) { return( DS_ERR|DS_FREAD_FAILED ); } if( dir_header.cbDirHeader != sizeof( dir_header ) || dir_header.cbDirEntry != sizeof( cv_directory_entry ) ) { return( DS_ERR|DS_INFO_INVALID ); } ii->dir_count = dir_header.cDir; block_count = BLOCK_FACTOR( ii->dir_count, DIRECTORY_BLOCK_ENTRIES ); ii->directory = DCAlloc( block_count * sizeof( cv_directory_entry * ) ); if( ii->directory == NULL ) { return( DS_ERR|DS_NO_MEM ); } memset( ii->directory, 0, block_count * sizeof( cv_directory_entry * ) ); i = 0; left = ii->dir_count; for( ;; ) { num = left; if( num > DIRECTORY_BLOCK_ENTRIES ) num = DIRECTORY_BLOCK_ENTRIES; block_size = num * sizeof( cv_directory_entry ); ii->directory[i] = DCAlloc( block_size ); if( ii->directory[i] == NULL ) { return( DS_ERR|DS_NO_MEM ); } if( DCRead( ii->sym_fid, ii->directory[i], block_size ) != block_size ) { return( DS_ERR|DS_FREAD_FAILED ); } ++i; left -= num; if( left == 0 ) { break; } } return( DS_OK ); }
static dip_status FindCV( dig_fhandle fid, unsigned long *offp, unsigned long *sizep ) { char sig[CV_SIG_SIZE]; dip_status ds; ds = TryFindPE( fid, offp, sizep ); if( ds & DS_ERR ) return( ds ); if( ds != DS_OK ) { ds = TryFindTrailer( fid, offp, sizep ); if( ds != DS_OK ) { return( ds ); } } if( DCSeek( fid, *offp, DIG_ORG ) != *offp ) { return( DS_ERR|DS_FSEEK_FAILED ); } if( DCRead( fid, sig, sizeof( sig ) ) != sizeof( sig ) ) { return( DS_ERR|DS_FREAD_FAILED ); } if( memcmp( sig, CV4_NB09, sizeof( sig ) ) != 0 ) { return( DS_FAIL ); } return( DS_OK ); }
static size_t BRead( FILE *fp, void *b, size_t s ) { size_t got; size_t want; if( s > sizeof( Buff.data ) ) { DCSeek( fp, Buff.fpos + Buff.off - Buff.len, DIG_ORG ); Buff.fpos = DCTell( fp ); Buff.len = 0; Buff.off = 0; if( Buff.fpos == DIG_SEEK_ERROR ) return( 0 ); got = DCRead( fp, b, s ); Buff.fpos += got; return( got ); } want = s; got = Buff.len - Buff.off; if( got > want ) got = want; memcpy( b, &Buff.data[Buff.off], got ); Buff.off += got; want -= got; if( want > 0 ) { size_t len; len = DCRead( fp, &Buff.data[0], sizeof( Buff.data ) ); if( len == DIG_RW_ERROR ) { Buff.fpos = DIG_SEEK_ERROR; Buff.off = 0; Buff.len = 0; return( DIG_RW_ERROR ); } Buff.len = len; Buff.fpos += Buff.len; b = (unsigned_8 *)b + got; memcpy( b, &Buff.data[0], want ); Buff.off = want; } return( s ); }
/* * Deals with LX and LE images. * We must try grab information from the object table. */ static dip_status FindHLLInLXImage( imp_image_handle *ii, unsigned long nh_off ) { union { os2_flat_header flat; object_record obj; } buf; dip_status rc; /* read the header */ rc = DCReadAt( ii->sym_file, &buf.flat, sizeof( buf.flat ), nh_off ); if( rc & DS_ERR ) { return( rc ); } rc = DS_FAIL; if( buf.flat.debug_off && buf.flat.debug_len ) { ii->is_32bit = 1; rc = FoundHLLSign( ii, buf.flat.debug_off, buf.flat.debug_len ); if( rc == DS_OK ) { unsigned i; /* * Get segment info from the object table. */ if ( DCSeek( ii->sym_file, buf.flat.objtab_off + nh_off, DIG_ORG ) != buf.flat.objtab_off + nh_off ) { return( DS_ERR | DS_FSEEK_FAILED ); } ii->seg_count = buf.flat.num_objects; ii->segments = DCAlloc( sizeof( hllinfo_seg ) * ii->seg_count ); if( ii->segments == NULL ) { return( DS_ERR | DS_NO_MEM ); } for( i = 0; i < ii->seg_count; i++ ) { if( DCRead( ii->sym_file, &buf.obj, sizeof( buf.obj ) ) != sizeof( buf.obj )) { return( DS_ERR | DS_FREAD_FAILED ); } ii->segments[i].is_executable = !!( buf.obj.flags & OBJ_EXECUTABLE ); ii->segments[i].is_16bit = !( buf.obj.flags & OBJ_BIG ); ii->segments[i].ovl = 0; ii->segments[i].map.offset = 0; ii->segments[i].map.segment = i + 1; ii->segments[i].size = buf.obj.size; ii->segments[i].address = buf.obj.addr; } } } return( rc ); }
/* * Checks if there is a tailing HLL signature in the file. * * This may work not work on executable images because of file alignments * imposed by the linker (ilink at least). However, TryFindInImage will * deal with those formats, so it doesn't really matter here. */ static dip_status TryFindTrailer( imp_image_handle *ii ) { hll_trailer sig; unsigned long pos; pos = DCSeek( ii->sym_file, DIG_SEEK_POSBACK( sizeof( sig ) ), DIG_END ); if( pos == DIG_SEEK_ERROR ) { return( DS_ERR | DS_FSEEK_FAILED ); } if( DCRead( ii->sym_file, &sig, sizeof( sig ) ) != sizeof( sig ) ) { return( DS_ERR | DS_FREAD_FAILED ); } if( !IsHllSignature( &sig ) ) { return( DS_FAIL ); } pos -= sig.offset - sizeof( sig ); return( FoundHLLSign( ii, pos, sig.offset - sizeof( sig ) ) ); }
static dip_status TryFindTrailer( dig_fhandle fid, unsigned long *offp, unsigned long *sizep ) { cv_trailer sig; unsigned long pos; pos = DCSeek( fid, DIG_SEEK_POSBACK( sizeof( sig ) ), DIG_END ); if( pos == DIG_SEEK_ERROR ) { return( DS_ERR|DS_FSEEK_FAILED ); } if( DCRead( fid, &sig, sizeof( sig ) ) != sizeof( sig ) ) { return( DS_ERR|DS_FREAD_FAILED ); } if( memcmp( sig.sig, CV4_NB09, sizeof( sig.sig ) ) != 0 ) { return( DS_FAIL ); } *sizep = sig.offset - sizeof( sig ); *offp = pos - *sizep; return( DS_OK ); }
/* * AllocLinkTable - allocate the demand load link table * */ static dip_status AllocLinkTable( section_info *inf, unsigned long num_links, unsigned long first_link ) { dword **lnk_tbl; dword *lnk; mod_table *tbl; unsigned num; unsigned long count; unsigned i; unsigned d; mod_info *mod; unsigned tbl_entries; dword end; info_block *blk; tbl_entries = ((num_links+(MAX_LINK_ENTRIES-1)) / MAX_LINK_ENTRIES) + 1; lnk_tbl = DCAlloc( tbl_entries * sizeof( dword * ) ); if( lnk_tbl == NULL ) { DCStatus( DS_ERR|DS_NO_MEM ); return( DS_ERR|DS_NO_MEM ); } for( i = 0; i < tbl_entries; ++i ) lnk_tbl[i] = NULL; inf->dmnd_link = lnk_tbl; i = 0; count = num_links; while( count != 0 ) { num = (count>MAX_LINK_ENTRIES) ? MAX_LINK_ENTRIES : count; lnk = DCAlloc( num*sizeof(dword)); if( lnk == NULL ) { DCStatus( DS_ERR|DS_NO_MEM ); return( DS_ERR|DS_NO_MEM ); } lnk_tbl[i++] = lnk; if( !inf->ctl->v2 ) { if( DCRead(inf->ctl->sym_file,lnk,num*sizeof(dword))!=num*sizeof(dword)) { DCStatus( DS_ERR|DS_FREAD_FAILED ); return( DS_ERR|DS_FREAD_FAILED ); } } count -= num; } lnk = *lnk_tbl; num = 0; count = 0; for( d = DMND_FIRST; d < DMND_NUM; ++d ) { for( blk = inf->mod_info; blk != NULL; blk = blk->next ) { tbl = blk->link; for( i = 0; i < tbl->count; ++i ) { mod = (mod_info *)((byte *)blk->info + tbl->mod_off[i]); if( inf->ctl->v2 ) { if( mod->di[d].u.size != 0 ) { if( num >= MAX_LINK_ENTRIES ) { lnk = *++lnk_tbl; num = 0; } lnk[num] = mod->di[d].info_off; end = lnk[num] + mod->di[d].u.size; mod->di[d].u.entries = 1; mod->di[d].info_off = count; ++num; ++count; } } else { if( mod->di[d].u.entries != 0 ) { mod->di[d].info_off = (mod->di[d].info_off-first_link)/sizeof(dword); } } } } } if( inf->ctl->v2 ) { if( num >= MAX_LINK_ENTRIES ) { lnk = *++lnk_tbl; num = 0; } lnk[num] = end; } return( DS_OK ); }
/* * Loads the HLL directory. * * 'offent' is the file offset of the first directory entry. */ static dip_status LoadDirectory( imp_image_handle *ii, unsigned long offent ) { unsigned block_count; unsigned i; unsigned left; size_t block_size; unsigned num; /* * Read the directory entries. We're using a two-level table here, * probably to avoid allocating big chunks of memory... */ block_count = BLOCK_FACTOR( ii->dir_count, DIRECTORY_BLOCK_ENTRIES ); ii->directory = DCAlloc( block_count * sizeof( void * ) ); if( ii->directory == NULL ) { return( DS_ERR | DS_NO_MEM ); } memset( ii->directory, 0, block_count * sizeof( void * ) ); /* skip to the first entry */ if( DCSeek( ii->sym_file, offent, DIG_ORG ) != offent) { return( DS_ERR | DS_FSEEK_FAILED ); } i = 0; left = ii->dir_count; do { num = left; if( num > DIRECTORY_BLOCK_ENTRIES ) { num = DIRECTORY_BLOCK_ENTRIES; } block_size = num * sizeof( hll_dir_entry ); ii->directory[i] = DCAlloc( block_size ); if( ii->directory[i] == NULL ) { return( DS_ERR | DS_NO_MEM ); } if( ii->format_lvl >= HLL_LVL_NB04 ) { if( DCRead( ii->sym_file, ii->directory[i], block_size ) != block_size ) { return( DS_ERR | DS_FREAD_FAILED ); } } else { /* Slow but simple. */ int j; hll_dir_entry *ent = ii->directory[i]; for( j = 0; j < num; j++, ent++ ) { cv3_dir_entry cv3ent; if( DCRead( ii->sym_file, &cv3ent, sizeof( cv3ent ) ) != sizeof( cv3ent ) ) { return( DS_ERR | DS_FREAD_FAILED ); } ent->subsection = cv3ent.subsection; ent->iMod = cv3ent.iMod; ent->lfo = cv3ent.lfo; ent->cb = cv3ent.cb; } } ++i; left -= num; } while( left != 0 ); return( DS_OK ); }
/* * Deals with 32-bit PE images. */ static dip_status FindHLLInPEImage( imp_image_handle *ii, unsigned long nh_off ) { dip_status rc; unsigned_32 debug_rva; unsigned_32 debug_len; unsigned_32 image_base; unsigned i; unsigned_32 sh_off; union { char sig[HLL_SIG_SIZE]; /* ASSUMES >= 4 */ unsigned_16 sig_16; unsigned_32 sig_32; pe_header pe; pe_object sh; debug_directory dbg_dir; } buf; /* read the header */ rc = DCReadAt( ii->sym_file, &buf.pe, sizeof( buf.pe ), nh_off ); if( rc & DS_ERR ) { return( rc ); } debug_rva = buf.pe.table[ PE_TBL_DEBUG ].rva; debug_len = buf.pe.table[ PE_TBL_DEBUG ].size; if( !debug_rva || !debug_len ) { return( DS_FAIL ); } ii->is_32bit = 1; image_base = buf.pe.image_base; /* * Translate the rva to a file offset and read necessary * segment information at the same time. */ ii->seg_count = buf.pe.num_objects; ii->segments = DCAlloc( sizeof( hllinfo_seg ) * buf.pe.num_objects ); if( ii->segments == NULL ) { return( DS_ERR | DS_NO_MEM ); } sh_off = nh_off /* vv -- watcom mixes the headers :-( */ + offsetof( pe_header, flags ) + sizeof( buf.pe.flags ) + buf.pe.nt_hdr_size; for ( i = 0; i < ii->seg_count; i++, sh_off += sizeof( buf.sh ) ) { rc = DCReadAt( ii->sym_file, &buf.sh, sizeof( buf.sh ), sh_off ); if ( rc & DS_ERR ) { return( rc ); } /* collect segment info. */ ii->segments[i].is_executable = !!( buf.sh.flags & PE_OBJ_CODE ); ii->segments[i].ovl = 0; ii->segments[i].map.offset = 0; ii->segments[i].map.segment = i + 1; ii->segments[i].size = buf.sh.virtual_size; // FIXME: alignment? ii->segments[i].address = buf.sh.rva + image_base; /* is the debug directory section? */ if( !ii->bias && debug_rva - buf.sh.rva < buf.sh.virtual_size ) { unsigned_32 debug_off; int left; debug_off = buf.sh.physical_offset + debug_rva - buf.sh.rva; /* * The IBM linker screw up here. It will omit the debug * directory and put the debug info there instead. * So, before scanning we'll have to check for any HLL sign. */ rc = DCReadAt( ii->sym_file, &buf.dbg_dir, sizeof( buf.dbg_dir ), debug_off ); if( rc & DS_ERR ) { return( rc ); } if( IsHllSignature( &buf ) ) { rc = FoundHLLSign( ii, debug_off, debug_len ); } else { left = debug_len / sizeof( debug_directory ); if( left < 16 ) left = 16; for ( ;; ) { if( buf.dbg_dir.debug_type == DEBUG_TYPE_CODEVIEW ) { /* found something? */ rc = FoundHLLSign( ii, buf.dbg_dir.data_seek, buf.dbg_dir.data_seek ); if( rc == DS_OK || rc & DS_ERR ) { break; } } /* next */ --left; if( left <= 0) { break; } if ( DCRead( ii->sym_file, &buf.dbg_dir, sizeof( buf.dbg_dir ) ) != sizeof( buf.dbg_dir ) ) { break; } } } if( rc & DS_ERR ) { return( rc ); } } } return( ii->bias ? DS_OK : DS_FAIL ); }
static dip_status TryFindPE( dig_fhandle h, unsigned long *offp, unsigned long *sizep ) { union { dos_exe_header dos; pe_header pe; } hdr; pe_object obj; unsigned_32 nh_off; unsigned_32 section_off; unsigned i; unsigned_32 debug_rva; debug_directory dir; if( DCSeek( h, 0, DIG_ORG ) != 0 ) { return( DS_ERR|DS_FSEEK_FAILED ); } if( DCRead( h, &hdr.dos, sizeof( hdr.dos ) ) != sizeof( hdr.dos ) ) { return( DS_ERR|DS_FREAD_FAILED ); } if( hdr.dos.signature != DOS_SIGNATURE ) { return( DS_FAIL ); } if( DCSeek( h, NH_OFFSET, DIG_ORG ) != NH_OFFSET ) { return( DS_ERR|DS_FSEEK_FAILED ); } if( DCRead( h, &nh_off, sizeof( nh_off ) ) != sizeof( nh_off ) ) { return( DS_ERR|DS_FREAD_FAILED ); } if( DCSeek( h, nh_off, DIG_ORG ) != nh_off ) { return( DS_ERR|DS_FSEEK_FAILED ); } if( DCRead( h, &hdr.pe, sizeof( hdr.pe ) ) != sizeof( hdr.pe ) ) { return( DS_FAIL ); } if( hdr.pe.signature != PE_SIGNATURE ) { return( DS_FAIL ); } if( hdr.pe.table[ PE_TBL_DEBUG ].rva == 0 ) { return( DS_FAIL ); } debug_rva = (hdr.pe.table[ PE_TBL_DEBUG ].rva / hdr.pe.object_align)* hdr.pe.object_align; section_off = nh_off + offsetof( pe_header, flags ) + sizeof( hdr.pe.flags ) + hdr.pe.nt_hdr_size; if( DCSeek( h, section_off, DIG_ORG ) != section_off ) { return( DS_ERR|DS_FSEEK_FAILED ); } for( i=0; i < hdr.pe.num_objects; i++ ) { if( DCRead( h, &obj, sizeof( obj ) ) != sizeof( obj ) ) { return( DS_ERR|DS_FREAD_FAILED ); } if( obj.rva == debug_rva ) { debug_rva = obj.physical_offset + hdr.pe.table[ PE_TBL_DEBUG ].rva - debug_rva; if( DCSeek( h, debug_rva, DIG_ORG ) != debug_rva ) { return( DS_ERR|DS_FSEEK_FAILED ); } if( DCRead( h, &dir, sizeof( dir ) ) != sizeof( dir ) ) { return( DS_ERR|DS_FREAD_FAILED ); } if( dir.debug_type != DEBUG_TYPE_CODEVIEW ) { return( DS_FAIL ); } *offp = dir.data_seek; *sizep = dir.debug_size; } } return( DS_FAIL ); }
void *VMBlock( imp_image_handle *iih, virt_mem start, size_t len ) { unsigned dir_idx; unsigned pg_idx; unsigned tmp_idx; unsigned i; unsigned j; unsigned num_pages; virt_mem pg_start; virt_page *pg; virt_page *zero; loaded_block *block; dir_idx = GET_DIR( start ); if( iih->virt[dir_idx] == NULL ) { if( !InitPageDir( iih, dir_idx ) ) { return( NULL ); } } pg_idx = GET_PAGE( start ); len += start % VM_PAGE_SIZE; pg_start = start & ~(virt_mem)(VM_PAGE_SIZE - 1); pg = iih->virt[dir_idx][pg_idx]; if( pg == NULL || ( pg->block->len - pg->offset ) < len ) { /* unloaded previously loaded block */ if( pg != NULL ) { tmp_idx = dir_idx; /* find first page of the block */ i = pg_idx; for( ;; ) { iih->virt[tmp_idx][i] = NULL; if( pg->offset == 0 ) break; if( i == 0 ) { --tmp_idx; i = DIR_SIZE; } --i; --pg; } DCFree( pg ); } num_pages = BLOCK_FACTOR( len, VM_PAGE_SIZE ); pg = DCAlloc( num_pages * ( sizeof( *pg ) + VM_PAGE_SIZE ) + sizeof( loaded_block ) - 1 ); if( pg == NULL ) { DCStatus( DS_ERR | DS_NO_MEM ); return( NULL ); } /* set up new page table entries */ block = (loaded_block *)&pg[num_pages]; tmp_idx = dir_idx; for( j = pg_idx, i = 0; i < num_pages; ++j, ++i ) { pg[i].block = block; pg[i].offset = i * VM_PAGE_SIZE; if( j >= DIR_SIZE ) { ++tmp_idx; j = 0; } if( iih->virt[tmp_idx] == NULL ) { if( !InitPageDir( iih, tmp_idx ) ) { /* unwind the setup already done */ num_pages = i; for( i = 0; i < num_pages; ++i, ++pg_idx ) { if( pg_idx >= DIR_SIZE ) { ++dir_idx; pg_idx = 0; } iih->virt[dir_idx][pg_idx] = NULL; } DCFree( pg ); return( NULL ); } } if( iih->virt[tmp_idx][j] != NULL ) { /* We just ran into another allocated block, so we have to kill all the pages mapped in by it. We know that if the page pointer is non-NULL, it will be offset==0 since KillPages will clean out the others. */ KillPages( iih, tmp_idx, j ); } iih->virt[tmp_idx][j] = &pg[i]; } /* read in new block */ len = num_pages * VM_PAGE_SIZE; block->len = len; pg_start += iih->bias; if( DCSeek( iih->sym_fp, pg_start, DIG_ORG ) ) { DCStatus( DS_ERR | DS_FSEEK_FAILED ); return( NULL ); } /* last block might be a short read */ if( DCRead( iih->sym_fp, pg->block->data, len ) == DIG_RW_ERROR ) { DCStatus( DS_ERR | DS_FREAD_FAILED ); return( NULL ); } pg = iih->virt[dir_idx][pg_idx]; } ++TimeStamp; if( TimeStamp == 0 ) { /* deal with wrap-around */ for( iih = ImageList; iih != NULL; iih = iih->next_image ) { if( iih->virt != NULL ) { for( i = iih->vm_dir_num; i-- > 0; ) { if( iih->virt[i] != NULL ) { for( j = DIR_SIZE; j-- > 0; ) { zero = iih->virt[i][j]; if( zero != NULL ) { zero->block->time_stamp = 0; } } } } } } ++TimeStamp; } pg->block->time_stamp = TimeStamp; return( &pg->block->data[(start & (VM_PAGE_SIZE - 1)) + pg->offset] ); }
/* * AllocLinkTable - allocate the demand load link table * */ static dip_status AllocLinkTable( section_info *inf, dword num_links, dword first_link ) { pointer_int **lnk_tbl; pointer_int *lnk; mod_table *tbl; unsigned num; dword count; unsigned i; demand_kind dk; mod_info *mod; unsigned tbl_entries; pointer_int end = 0; info_block *blk; #if defined( _M_X64 ) unsigned j; #endif tbl_entries = ( ( num_links + ( MAX_LINK_ENTRIES - 1 ) ) / MAX_LINK_ENTRIES ) + 1; lnk_tbl = DCAlloc( tbl_entries * sizeof( pointer_int * ) ); if( lnk_tbl == NULL ) { DCStatus( DS_ERR|DS_NO_MEM ); return( DS_ERR|DS_NO_MEM ); } for( i = 0; i < tbl_entries; ++i ) lnk_tbl[i] = NULL; inf->dmnd_link = lnk_tbl; i = 0; num = MAX_LINK_ENTRIES; for( count = num_links; count > 0; count -= num ) { if( num > count ) num = count; lnk = DCAlloc( num * sizeof( pointer_int ) ); if( lnk == NULL ) { DCStatus( DS_ERR|DS_NO_MEM ); return( DS_ERR|DS_NO_MEM ); } lnk_tbl[i++] = lnk; if( !inf->ctl->v2 ) { if( DCRead( inf->ctl->sym_fid, lnk, num * sizeof( dword ) ) != num * sizeof( dword ) ) { DCStatus( DS_ERR|DS_FREAD_FAILED ); return( DS_ERR|DS_FREAD_FAILED ); } #if defined( _M_X64 ) for( j = num; j-- > 0; ) { lnk[j] = ((dword *)lnk)[j]; } #endif } } lnk = *lnk_tbl; num = 0; count = 0; for( dk = 0; dk < MAX_DMND; ++dk ) { for( blk = inf->mod_info; blk != NULL; blk = blk->next ) { tbl = blk->link; for( i = 0; i < tbl->count; ++i ) { mod = (mod_info *)((byte *)blk->info + tbl->mod_off[i]); if( inf->ctl->v2 ) { if( mod->di[dk].u.size != 0 ) { if( num >= MAX_LINK_ENTRIES ) { lnk = *++lnk_tbl; num = 0; } lnk[num] = mod->di[dk].info_off; end = lnk[num] + mod->di[dk].u.size; mod->di[dk].u.entries = 1; mod->di[dk].info_off = count; ++num; ++count; } } else { if( mod->di[dk].u.entries != 0 ) { mod->di[dk].info_off = ( mod->di[dk].info_off - first_link ) / sizeof( pointer_int ); } } } } } if( inf->ctl->v2 ) { if( num >= MAX_LINK_ENTRIES ) { lnk = *++lnk_tbl; num = 0; } lnk[num] = end; } return( DS_OK ); }