/* * 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 ); }
/* * Tries to find the HLL/CV debug info in a image which format we know. * This function knows about LX, LE, PE and watcom symfile images. */ static dip_status TryFindInImage( imp_image_handle *ii ) { 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; bool have_mz_header = FALSE; unsigned_32 nh_off; dip_status rc; /* Read the image header. */ rc = DCReadAt( ii->sym_file, &buf.sig, sizeof( buf.sig ), 0 ); if( rc & DS_ERR ) { return( rc ); } nh_off = 0; if( buf.sig_16 == DOS_SIGNATURE ) { have_mz_header = TRUE; /* read the new exe header */ rc = DCReadAt( ii->sym_file, &nh_off, sizeof( nh_off ), NH_OFFSET ); if( rc & DS_ERR ) { return( rc ); } rc = DCReadAt( ii->sym_file, &buf.sig, sizeof( buf.sig ), nh_off ); if( rc & DS_ERR ) { return( rc ); } } /* * LE/LX executable - Use the debug_off/len members of the header. */ if( buf.sig_16 == OSF_FLAT_LX_SIGNATURE || buf.sig_16 == OSF_FLAT_SIGNATURE ) { return( FindHLLInLXImage( ii, nh_off ) ); } /* * PE executable - Use or scan the debug directory. */ if( buf.sig_32 == PE_SIGNATURE ) { return( FindHLLInPEImage( ii, nh_off ) ); } /* * NE and MZ executables do not contain any special information * in the header. TryFindTrailer() will have to pick up the debug data. */ if( (buf.sig_16 == OS2_SIGNATURE_WORD) || have_mz_header ) { ii->is_32bit = 0; } /* * ELF executable - ?????? */ /* * A watcom .sym file. */ if( IsHllSignature( &buf ) ) { return( FoundHLLSign( ii, nh_off, ~0UL ) ); } /* no idea what this is.. */ return( DS_FAIL ); }
/* * 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 ); }
/* * Validates the signatures of a HLL debug info block, determining * the length if necessary. */ static dip_status FoundHLLSign( imp_image_handle *ii, unsigned long off, unsigned long size ) { dip_status rc; hll_trailer hdr; unsigned long off_dirent, off_trailer; /* read the header. */ rc = DCReadAt( ii->sym_file, &hdr, sizeof( hdr ), off ); if( rc & DS_ERR) { return rc; } if( !IsHllSignature( &hdr ) ) { return DS_FAIL; } /* * Read the directory info - both to verify it and to find the trailer. */ off_dirent = off + hdr.offset; if( !memcmp( hdr.sig, HLL_NB04, HLL_SIG_SIZE ) ) { hll_dirinfo dir_hdr; rc = DCReadAt( ii->sym_file, &dir_hdr, sizeof( dir_hdr ), off_dirent ); if( rc & DS_ERR) { return rc; } if( dir_hdr.cbDirHeader != sizeof( hll_dirinfo ) || dir_hdr.cbDirEntry != sizeof( hll_dir_entry ) ) { return DS_FAIL; } ii->dir_count = dir_hdr.cDir; off_dirent += sizeof( dir_hdr ); off_trailer = off_dirent + sizeof( hll_dir_entry ) * dir_hdr.cDir; } else { /* Old CV3 directory. */ cv3_dirinfo dir_hdr; rc = DCReadAt( ii->sym_file, &dir_hdr, sizeof( dir_hdr ), off_dirent ); if( rc & DS_ERR) { return rc; } ii->dir_count = dir_hdr.cDir; off_dirent += sizeof( dir_hdr ); off_trailer = off_dirent + sizeof( cv3_dir_entry ) * dir_hdr.cDir; } /* is the trailer following the directory? It usually is with wlink. */ rc = DCReadAt( ii->sym_file, &hdr, sizeof( hdr ), off_trailer ); if( rc & DS_ERR) { return rc; } if( !IsHllSignature( &hdr ) ) { /* * No it isn't, seek from the end (off + size). * Adjust the length first. */ long cur; unsigned overlap = 0; cur = DCSeek( ii->sym_file, 0, DIG_END ); if( cur > size + off && size + off > size ) { cur = off + size; } hdr.sig[0] = 0; do { char buf[1024 + sizeof( hdr )]; size_t to_read; char *ptr; /* read block */ to_read = 1024 + overlap; cur -= 1024; if( cur < off_trailer ) { to_read += off_trailer - cur; cur = off_trailer; } if( to_read < sizeof( hdr) ) { return DS_FAIL; } rc = DCReadAt( ii->sym_file, buf, to_read, cur ); if( rc & DS_ERR ) { return rc; } /* search it */ for( ptr = &buf[to_read - sizeof( hdr )]; ptr >= &buf[0]; ptr--) { if( IsHllSignature(ptr) ) { off_trailer = cur + ptr - &buf[0]; hdr = *(hll_trailer *)ptr; break; } } /* next */ overlap = sizeof( hdr ); } while( hdr.sig[0] == 0 ); } /* * Validate the trailer offset (=size). */ if( off_trailer == off || hdr.offset != off_trailer - off + sizeof( hdr ) ) { return( DS_FAIL ); } /* * We're good. */ ii->bias = off; ii->size = off_trailer - off + sizeof( hdr ); if ( !memcmp( hdr.sig, HLL_NB04, HLL_SIG_SIZE ) ) { ii->format_lvl = HLL_LVL_NB04; } else if ( !memcmp( hdr.sig, HLL_NB02, HLL_SIG_SIZE ) ) { ii->format_lvl = HLL_LVL_NB02; } else if( !memcmp( hdr.sig, HLL_NB00, HLL_SIG_SIZE ) ) { ii->format_lvl = ii->is_32bit ? HLL_LVL_NB00_32BIT : HLL_LVL_NB00; } else { hllConfused(); } /* * Since we already know where the directory is, we load it here. */ rc = LoadDirectory( ii, off_dirent ); return( rc ); }