📄 bdiff.c
字号:
stats( "\n" );
return( 0 );
}
}
}
AddDiff( new_blk->start, new_blk->length );
stats( " (changed)\n" );
return( 0 );
}
int only_new_walker( exe_blk *new_blk, void *parm )
{
fpos_t len;
walker_data *last;
exe_mod *new_mod;
auto exe_mod tmp_mod;
last = parm;
tmp_mod.mod_offset = new_blk->mod_offset;
new_mod = SymFind( new.mods_by_offset, &tmp_mod );
if( new_mod == NULL ) {
fatal( MSG_DEBUG_INFO );
}
if( last->last_offset != new_blk->start ) {
len = new_blk->start - last->last_offset;
stats( "[%lx-%lx) ???",last->last_offset, last->last_offset + len );
if( FindBlockInOld( last->last_offset, len ) ) {
stats( "\n" );
} else {
stats( " (NOT found)\n" );
}
}
last->last_offset = new_blk->start + new_blk->length;
stats( "[%lx-%lx) ", new_blk->start, last->last_offset );
printd( new_mod->name );
if( new_blk->start >= EndNew ) {
stats( " (BSS block ignored)\n" );
return( 0 );
}
if( FindBlockInOld( new_blk->start, new_blk->length ) ) {
stats( "\n" );
} else {
stats( " (NOT found)\n" );
}
return( 0 );
}
fpos_t ExeOverlayAccess( exe_form_t exe, uint_16 section, uint_16 *seg )
{
exe = exe;
return( section - *seg );
}
//#ifdef USE_DBGINFO
void ProcessExe( char *name, char *sym_name, exe_info *exe )
{
unsigned num_blks;
exe_mod *new_mod;
exe_mod *found_mod;
exe_blk *new_blk;
fpos_t first_section;
fpos_t mod_list;
fpos_t addr_list;
fpos_t curr_offset;
fpos_t debug_header;
addr48_ptr seg_addr;
auto master_dbg_header dbg_head;
auto section_dbg_header section_head;
auto seg_info seg_desc;
auto mod_info mod_name;
auto addr_info seg_chunk;
auto exe_mod tmp_mod;
char msgbuf[80];
_splitpath( name, drive, dir, fname, ext );
if( ext[0] == '\0' ) {
strcpy( ext, ".exe" );
}
_makepath( buff, drive, dir, fname, ext );
exe->fd = open( buff, O_RDONLY|O_BINARY );
if( exe->fd == -1 ) {
IOError( buff );
}
_splitpath( sym_name, drive, dir, fname, ext );
if( ext[0] == '\0' ) {
strcpy( ext, ".sym" );
}
_makepath( buff, drive, dir, fname, ext );
exe->sym.fd = open( buff, O_RDONLY|O_BINARY );
if( exe->sym.fd == -1 ) {
IOError( buff );
}
xseek( exe->sym.fd, - sizeof( dbg_head ), SEEK_END );
debug_header = lseek( exe->sym.fd, 0, SEEK_CUR );
xread( exe->sym.fd, &dbg_head, sizeof( dbg_head ) );
if( dbg_head.signature != VALID_SIGNATURE ||
dbg_head.exe_major_ver != EXE_MAJOR_VERSION ||
dbg_head.exe_minor_ver > EXE_MINOR_VERSION ||
dbg_head.obj_major_ver != OBJ_MAJOR_VERSION ||
dbg_head.obj_minor_ver > OBJ_MINOR_VERSION ) {
fatal( MSG_DEBUG_INFO );
}
exe->sym.start = lseek( exe->sym.fd, 0, SEEK_END ) - dbg_head.debug_size;
/* get segment positions in executable */
first_section = exe->sym.start + dbg_head.lang_size + dbg_head.segment_size;
xseek( exe->sym.fd, first_section, SEEK_SET );
xread( exe->sym.fd, §ion_head, sizeof( section_head ) );
if( section_head.mod_offset >= section_head.gbl_offset ||
section_head.gbl_offset >= section_head.addr_offset ||
section_head.addr_offset >= section_head.section_size ) {
fatal( MSG_DEBUG_INFO );
}
exe->mods_by_offset = SymInit( cmp_mod_offset );
exe->mods_by_name = SymInit( cmp_mod_name );
mod_list = first_section + section_head.mod_offset;
xseek( exe->sym.fd, mod_list, SEEK_SET );
curr_offset = section_head.mod_offset;
while( curr_offset != section_head.gbl_offset ) {
xread( exe->sym.fd, &mod_name, sizeof( mod_name ) );
new_mod = _allocate( sizeof( exe_mod ) + mod_name.name[0] );
if( new_mod == NULL ) {
GetMsg( msgbuf, ERR_MEMORY_OUT );
puts( msgbuf );
MsgFini();
exit( EXIT_FAILURE );
}
new_mod->blocks = NULL;
new_mod->mod_offset = curr_offset - section_head.mod_offset;
new_mod->name[0] = mod_name.name[0];
xread( exe->sym.fd, &new_mod->name[1], mod_name.name[0] );
SymAdd( exe->mods_by_offset, new_mod );
SymAdd( exe->mods_by_name, new_mod );
curr_offset += sizeof( mod_name ) + mod_name.name[0];
}
if( exe == &new ) {
new.blks = SymInit( cmp_blk );
}
if( first_section + section_head.section_size != debug_header ) {
fatal( MSG_OVERLAYS );
}
exe->form = ExeForm( exe->fd, 0, exe );
addr_list = first_section + section_head.addr_offset;
xseek( exe->sym.fd, addr_list, SEEK_SET );
curr_offset = section_head.addr_offset;
while( curr_offset != section_head.section_size ) {
xread( exe->sym.fd, &seg_desc, sizeof(seg_info) - sizeof(addr_info) );
curr_offset += sizeof( seg_info ) - sizeof( addr_info );
num_blks = seg_desc.num;
seg_addr = seg_desc.base;
while( num_blks != 0 ) {
xread( exe->sym.fd, &seg_chunk, sizeof( seg_chunk ) );
curr_offset += sizeof( seg_chunk );
tmp_mod.mod_offset = seg_chunk.mod;
found_mod = SymFind( exe->mods_by_offset, &tmp_mod );
if( found_mod == NULL ) {
fatal( MSG_DEBUG_INFO );
}
new_blk = _allocate( sizeof( *new_blk ) );
if( new_blk == NULL ) {
GetMsg( msgbuf, ERR_MEMORY_OUT );
puts( msgbuf );
MsgFini();
exit( EXIT_FAILURE );
}
new_blk->next = found_mod->blocks;
found_mod->blocks = new_blk;
new_blk->start = ExeTransformAddr( exe->form,
seg_addr.segment, seg_addr.offset,
section_head.section_id );
seg_addr.offset += seg_chunk.size;
new_blk->length = seg_chunk.size;
new_blk->mod_offset = found_mod->mod_offset;
if( exe == &new ) {
SymAdd( new.blks, new_blk );
}
--num_blks;
}
}
}
void SymbolicDiff( algorithm alg, char *old_exe, char *new_exe )
{
auto walker_data data;
data.last_offset = 0;
ProcessExe( new_exe, NewSymName, &new );
if( alg == ALG_BOTH ) {
ProcessExe( old_exe, OldSymName, &old );
SymWalk( new.blks, &data, both_walker );
close( old.fd );
close( old.sym.fd );
} else {
SymWalk( new.blks, &data, only_new_walker );
}
close( new.fd );
close( new.sym.fd );
}
#endif
void VerifyCorrect( char *name )
{
/* Try the patch file and ensure it produces new from old */
char *real_new;
foff offset;
memset( NewFile, 0x00, EndNew );
Execute( NewFile );
_free( OldFile );
real_new = ReadIn( name, EndNew, EndNew );
if( real_new != NULL ) {
if( memcmp( real_new, NewFile, EndNew ) != 0 ) {
offset = 0;
for(;;) {
if( *real_new != *NewFile ) {
PatchError( ERR_PATCH_BUNGLED, offset, *real_new, *NewFile );
}
++offset;
if( offset >= EndNew ) break;
++real_new;
++NewFile;
}
}
_free( real_new );
}
}
int HoleCompare(const void *_h1, const void *_h2)
{
const region *h1 = _h1;
const region *h2 = _h2;
if( h1->diff < h2->diff ) return( -1 );
if( h1->diff > h2->diff ) return( 1 );
if( h1->new_start < h2->new_start ) return( -1 );
if( h1->new_start > h2->new_start ) return( 1 );
return( 0 );
}
#define OutPatch( val, type ) {CheckPatch( sizeof(type) );*(type*)CurrPatch=(val);CurrPatch+=sizeof(type);}
/*
* Output the offset to the next hole with the same difference value.
* as follows:
* 0xxxxxxx - value xxxxxxx ( 0 .. 127 )
* 10xxxxxx yyyyyyyy - value xxxxxxyyyyyyyy ( 0 .. 16383 )
* 11xxxxxx yyyyyyyy zzzzzzzz - value xxxxxxyyyyyyyyzzzzzzzz ( 0 .. 2**30-1 )
*/
int OutVar( foff value, int really )
{
if( value <= 0x7f ) {
if( really ) {
OutPatch( value & 0x7f, byte ); /* top bit off */
}
return( 0 );
} else if( value <= 0x3fff ) { /* top bit on, next bit off */
if( really ) {
OutPatch( 0x80 | ( ( value >> 8 ) & 0x3f ), byte );
OutPatch( value & 0xff, byte );
}
return( 1 );
} else { /* top two on */
if( really ) {
OutPatch( 0xC0 | ( ( value >> 16 ) & 0x3f ), byte );
OutPatch( ( value >> 8 ) & 0xff, byte );
OutPatch( value & 0xff, byte );
}
return( 2 );
}
}
void OutStr( char *str )
{
for( ;; ) {
if( *str == '\0' ) break;
OutPatch( *str, char );
++str;
}
}
#define MIN_ITERS (sizeof(patch_cmd)+sizeof(hole)+sizeof(foff)+sizeof(foff))
int FOffCompare(const void *_h1, const void *_h2)
{
const region *h1 = _h1;
const region *h2 = _h2;
if( h1->new_start < h2->new_start ) return( -1 );
if( h1->new_start > h2->new_start ) return( 1 );
return( 0 );
}
#define RUN_SIZE 5
long HolesToDiffs( void )
{
/* Find runs of holes which would be cheaper to represent as differences */
region *curr;
region *next;
region *end;
region *run_start;
region *run;
long hole_size;
long diff_size;
long dead_holes;
long savings;
savings = 0;
if( NumHoles != 0 ) {
/* sort by file offset */
qsort(HoleArray, NumHoles, sizeof( region ), FOffCompare );
end = HoleArray + NumHoles - 1;
next = HoleArray+1;
curr = HoleArray;
dead_holes = 0;
savings = 0;
/* going through the array in adjacent pairs, (curr, next) ... */
for( ;; ) {
/* find two holes which are the same small amount apart */
for( ;; ) {
if( curr >= end ) break;
if( next->old_start - curr->old_start
!= next->new_start - curr->new_start ) break;
if( next->old_start - curr->old_start <= RUN_SIZE ) break;
++next;
++curr;
}
if( curr >= end ) break;
/* extend this run while holes are the same small distance apart */
run_start = curr;
for( ;; ) {
++next;
++curr;
if( curr >= end ) break;
if( next->old_start - curr->old_start
!= next->new_start - curr->new_start ) break;
if( next->old_start - curr->old_start > RUN_SIZE ) break;
}
if( curr >= end ) break;
/* convert to a difference region if it would make patch smaller */
hole_size = 0;
diff_size = 2*sizeof(foff)+sizeof(patch_cmd)
+ curr->new_start - run_start->new_start + sizeof(hole);
for( run = run_start; run <= curr; ++run ) {
if( run->dependants == 1 ) hole_size += run->size;
}
if( hole_size > diff_size ) {
savings += hole_size - diff_size;
AddRegion( &DiffRegions, run_start->old_start,
run_start->new_start,
curr->new_start-run_start->new_start+sizeof(hole) );
for( run = run_start; run <= curr; ++run ) {
++dead_holes;
run->diff = 0;
run->new_start = 0;
}
++curr;
next = curr+1;
}
}
/* sort by difference amount. This moves dead holes to the front */
SortHoleArray();
/* Get rid of dead holes (Those converted to difference regions) */
NumHoles -= dead_holes;
memmove( HoleArray, HoleArray+dead_holes, NumHoles * sizeof( region ) );
}
return( savings );
}
void ProcessHoleArray( int write_holes )
{
/* write holes out to the patch file, or just calculate file size needed */
region *curr;
region *curr_header;
region *end_iters;
region *prev;
region *end;
hole curr_diff;
hole diff;
foff curr_start;
int first;
foff iters;
foff incr;
int size;
if( NumHoles != 0 ) {
end = HoleArray + NumHoles - 1;
first = 1;
for( curr = HoleArray; curr <= end; ++curr ) {
diff = curr->diff;
prev = curr;
curr->dependants = 1;
incr = 0;
iters = 1;
for( end_iters = curr + 1; end_iters <= end; ++end_iters ) {
if( diff != end_iters->diff ) break;
if( incr != 0
&& incr != end_iters->new_start - prev->new_start ) break;
incr = end_iters->new_start - prev->new_start;
++iters;
prev = end_iters;
}
if( iters > MIN_ITERS ) {
if( write_holes ) {
if( !first ) {
OutPatch( 0, byte );
}
HoleHeaders++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -