1 /*
* android_vmm.c
*
* This is the startup code of the Android VMM
*
* Naveen Kalla, Scott A, Patrice G
* For this code to run directly from Flash, all constant variables must
* be marked with 'const' and all other variables initialized at run-time
* only. This way all non constant variables will end up in the bss segment,
* which should point to addresses in RAM and cleared to 0 on start.
* This allows for a much quicker boot time.
*
*/
#include <linux/string.h>
#include "vmstate.h"
#include "stdio.h"
#include "mm.h"
#include <asm-arm/domain.h>
#define __ptr_t void *
#define FIRST_VM_ADDR 0x200000
#define KERNEL_ARGS_ADDR 0x100
#define KERNEL_LOAD_ADDR 0x00010000
#define INITRD_LOAD_ADDR 0x00800000
#define NEW_VMM_LOC ( 94 * 1024 * 1024 )
/* Needs to be at a 16K boundary. So leave enough space for alignment */
const unsigned long pg_directory[4096 + 4096];
/* Keep space for page tables for VM1. Since this folliows page directory
* above, the page tables will follow the above table */
/* 20 page tables allows for 20 * 4 MB memory */
const unsigned long pg_tbls[( 1024 ) * 20];
/* Page tables will be just above the location where the VMs will be loaded */
/* Leave space for one large page table and one small page table */
//#define PGTBL_BASE ( ( FIRST_VM_ADDR - ( 4096*4+1024*4+256*4 ) ) & 0xFFFF0000 )
#define PG_DIR_BASE ( ( unsigned long )( &pg_directory[4096] ) & 0xFFFFC000 )
#define RAM_SIZE_FOR_VM 32*1024*1024
extern char input_kernel[];
extern char input_kernel_end[];
extern char input_rd[];
extern char input_rd_end[];
phys_mem_t mem_map[10];
CP15Regs cp15regs;
const phys_mem_t memory_map[] = {
/* Android VMM space */
{
0,
( FIRST_VM_ADDR - 1 ),
0,
SECTION,
SVC_READWRITE,
VM_FLAG_CACHEABLE | VM_FLAG_BUFFERABLE
},
/* Android Kernel Space */
{
FIRST_VM_ADDR,
( RAM_SIZE_FOR_VM + FIRST_VM_ADDR - 1 ),
FIRST_VM_ADDR,
PAGES,
FULL_ACCESS,
//SVC_READWRITE,
VM_FLAG_CACHEABLE | VM_FLAG_BUFFERABLE
},
/* Android Kernel Space */
{
( RAM_SIZE_FOR_VM + FIRST_VM_ADDR ),
( NEW_VMM_LOC - 1 ),
( RAM_SIZE_FOR_VM + FIRST_VM_ADDR ),
FAULT,
FULL_ACCESS,
//SVC_READWRITE,
VM_FLAG_CACHEABLE | VM_FLAG_BUFFERABLE
},
/* Android VMM space */
{
NEW_VMM_LOC,
( NEW_VMM_LOC + FIRST_VM_ADDR - 1 ),
NEW_VMM_LOC,
SECTION,
SVC_READWRITE,
VM_FLAG_CACHEABLE | VM_FLAG_BUFFERABLE
},
};
const phys_mem_t mem_map_vm1[] = {
/* Android Kernel Space */
{
FIRST_VM_ADDR,
( RAM_SIZE_FOR_VM + FIRST_VM_ADDR - 1 ),
FIRST_VM_ADDR,
LARGEPAGES,
FULL_ACCESS,
//SVC_READWRITE,
VM_FLAG_CACHEABLE | VM_FLAG_BUFFERABLE
}
};
/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */
static uint32_t bootloader[] = {
0xe3a00000, /* mov r0, #0 */
0xe3a01000, /* mov r1, #0x?? */
0xe3811c00, /* orr r1, r1, #0x??00 */
0xe59f2000, /* ldr r2, [pc, #0] */
0xe59ff000, /* ldr pc, [pc, #0] */
0, /* Address of kernel args. Set by integratorcp_init. */
0 /* Kernel entry point. Set by integratorcp_init. */
};
static int number_of_vms = 1;
static VMState android_vm_table[5];
VMState *curr_vm;
typedef void ( *boot_fn )( void );
boot_fn vm_boot;
130 static void set_kernel_args( uint32_t loader_start, uint32_t ram_size, int initrd_size,
const char *kernel_cmdline )
{
uint32_t *p;
p = ( uint32_t * )( loader_start + KERNEL_ARGS_ADDR );
/* ATAG_CORE */
*p = 5; p++;
*p = 0x54410001; p++;
*p = 1; p++;
*p = 0x1000; p++;
*p = 0; p++;
/* ATAG_MEM */
*p = 4; p++;
*p = 0x54410002; p++;
*p = ram_size; p++;
*p = 0; p++;
if ( initrd_size ) {
/* ATAG_INITRD2 */
*p = 4; p++;
*p = 0x54420005; p++;
*p = INITRD_LOAD_ADDR; p++;
*p = initrd_size; p++;
}
if ( kernel_cmdline && *kernel_cmdline ) {
/* ATAG_CMDLINE */
int cmdline_size;
cmdline_size = strlen( kernel_cmdline );
memcpy ( p + 2, kernel_cmdline, cmdline_size + 1 );
cmdline_size = ( cmdline_size >> 2 ) + 1;
*p = cmdline_size + 2; p++;
*p = 0x54410009; p++;
p += cmdline_size;
}
/* ATAG_END */
*p = 0; p++;
*p = 0; p++;
}
170 void read_cp15_regs( void )
{
unsigned int *page_dir_ptr;
unsigned long num_entries;
asm( "mrc p15, 0, %0, c2, c0\n\t"
"mrc p15, 0, %1, c3, c0\n"
: "=r" ( cp15regs.transbase ), "=r" ( cp15regs.dac ) );
asm( "mrc p15, 0, %0, c1, c0\n" : "=r" ( cp15regs.ctrl ) );
printf( "Control: %08x Table: %08x DAC: %08x \n",
cp15regs.ctrl, cp15regs.transbase, cp15regs.dac );
page_dir_ptr = ( unsigned int * )( cp15regs.transbase );
//for( int cnt = 0; cnt < 0x1000; cnt += 0x100 )
//{
// printf( "Translation Table [%x] = %08x\n", cnt, page_dir_ptr[cnt] );
//}
// Read memory map for the first 2M. Assuming this is max size fo VMM
printf( "Translation Table [%x] = %08x\n", 0, page_dir_ptr[0] );
printf( "Translation Table [%x] = %08x\n", 1, page_dir_ptr[1] );
// Since page dir is at 16K. Add two entries at 254M
printf( "Translation Table [%x] = %08x\n", 94, page_dir_ptr[94] );
printf( "Translation Table [%x] = %08x\n", 95, page_dir_ptr[95] );
}
201 void relocate_vmm( void )
{
// Move VMM to higher part of conventional memory
// Copy the contents from 0-2M to Ram size - 2M
memcpy( ( uint8_t * )NEW_VMM_LOC, ( uint8_t * ) 0, ( 2*1024 *1024 ) );
// Jump to VMM in higher memory
// Use the Page tables and Page Dir from higher VM
cp15regs.transbase += NEW_VMM_LOC;
cp15regs.ctrl &= ~5;
asm( "mcr p15, 0, %0, c1, c0, 0\n\t"
: "=r" ( cp15regs.ctrl ) );
asm( "mcr p15, 0, %0, c2, c0, 0\n\t"
: "=r" ( cp15regs.transbase ) );
cp15regs.ctrl |= 5;
asm( "mcr p15, 0, %0, c1, c0, 0\n\t"
: "=r" ( cp15regs.ctrl ) );
/*
num_entries = create_mem_map( ( unsigned long * )page_dir_ptr, mem_map );
printf( "num_entries = %8lx \n", num_entries );
for( cnt = 0; cnt<num_entries; cnt++ )
{
printf( "mem_map[%d].virt_addr_start = %8lx\n",
cnt, mem_map[cnt].virt_addr_start );
printf( "mem_map[%d].virt_addr_end = %8lx\n",
cnt, mem_map[cnt].virt_addr_end );
printf( "mem_map[%d].phys_addr = %8lx\n",
cnt, mem_map[cnt].phys_addr );
printf( "mem_map[%d].entrytype = %8lx\n",
cnt, mem_map[cnt].entrytype );
printf( "mem_map[%d].access = %x\n",
cnt, mem_map[cnt].access );
}
*/
return;
}
249 unsigned int remap_mmu( void )
{
unsigned long *page_dir_ptr;
int cnt;
volatile unsigned int transbase;
// Page tables will be stored before the FIRST_VM_ADDR.
// Currently assuming that we have one level-1 descriptor table and
// two level-2 descriptor tables ( one for course grained and one for
// fine grained
create_pg_dir( ( phys_mem_t * )memory_map,
( sizeof( memory_map ) / sizeof( *memory_map ) ),
( unsigned long* )PG_DIR_BASE );
page_dir_ptr = ( unsigned long * )PG_DIR_BASE;
for( cnt = 0; cnt < 0x23; cnt += 0x1 )
{
printf( "Page Dir [%x] = %08lx\n", cnt, page_dir_ptr[cnt] );
}
create_pg_table( ( phys_mem_t * )mem_map_vm1,
( sizeof( mem_map_vm1 ) / sizeof( *mem_map_vm1 ) ),
( unsigned long * )PG_DIR_BASE + 4096 );
cp15regs.transbase = ( unsigned int )PG_DIR_BASE;
cp15regs.dac = 0xFFFFFF00 | ( FULL_ACCESS << ( DOMAIN_MANAGER << 1 ) ) |
( NO_USR_WRITE << ( 2 << 1 ) ) |
( SVC_READWRITE << ( DOMAIN_CLIENT << 1 ) ) |
( NO_ACCESS <<( DOMAIN_NOACCESS << 1 ) );
cp15regs.ctrl &= ~5;
asm( "mcr p15, 0, %0, c1, c0, 0\n\t"
: "=r" ( cp15regs.ctrl ) );
asm( "mcr p15, 0, %0, c3, c0, 0\n\t"
: "=r" ( cp15regs.dac ) );
asm( "mcr p15, 0, %0, c2, c0, 0\n\t"
: "=r" ( cp15regs.transbase ) );
cp15regs.ctrl |= 5;
asm( "mcr p15, 0, %0, c1, c0, 0\n\t"
: "=r" ( cp15regs.ctrl ) );
printf( "Loaded Page tables. Rereading them\n" );
// read_cp15_regs( );
return;
}
304 void android_vmm( void )
{
int i, j;
unsigned long stack_ptr, prg_ctr, link_reg;
unsigned long cpsr_value;
putstr( "Running Android VMM............. \n" );
asm( "mrs %0, cpsr\n\t"
: "=r" ( cpsr_value ) );
printf( "CPSR = %lx\n", cpsr_value );
read_cp15_regs( );
remap_mmu( );
relocate_vmm( );
asm( "add sp, sp, #98566144" );
asm( "add pc, pc, #98566144" );
asm( "add lr, lr, #98566144" );
printf( "Domain val %d, %d = %d DAC = %lx\n",
DOMAIN_USER,
DOMAIN_MANAGER,
domain_val( DOMAIN_USER, DOMAIN_MANAGER ),
cp15regs.dac );
asm( "mov %0, sp"
: "=r" ( stack_ptr ) );
asm( "mov %0, pc"
: "=r" ( prg_ctr ) );
asm( "mov %0, lr"
: "=r" ( link_reg ) );
//asm( "mrc p15, 0, %0, c1, c0\n" : "=r" ( ctrl ) );
printf( "stack = %08lx, pc = %08lx\n", stack_ptr, prg_ctr );
android_vm_table[0].kernel_location = &input_kernel[0];
android_vm_table[0].kernel_size = &input_kernel_end[0] - &input_kernel[0];
android_vm_table[0].initrd_location = &input_rd[0];
android_vm_table[0].ramdisk_size = &input_rd_end[0] - &input_rd[0];
android_vm_table[0].loader_start = FIRST_VM_ADDR;
//android_vm_table[0].loader_start = 0;
for ( i = 0; i < number_of_vms; i++ )
{
printf( "%d Kernel Location = %p size = %d \n data = ",
i+1,
android_vm_table[i].kernel_location,
android_vm_table[0].kernel_size );
for( j=0; j < 20; j++ )
{
printf( "%x ", android_vm_table[i].kernel_location[j] );
}
putstr( "\n" );
printf( "Ramdisk Location = %p size = %d \n data = ",
android_vm_table[i].initrd_location,
android_vm_table[0].ramdisk_size );
for( j=0; j < 20; j++ )
{
printf( "%x ", android_vm_table[i].initrd_location[j] );
}
putstr( "\n" );
}
putstr( "Loading the first VM...\n" );
/*
* Makesure boot_loader is not running at the address where
* the kernel and ramdisk need to be loaded
*/
asm( "mrs %0, cpsr\n\t"
: "=r" ( cpsr_value ) );
cpsr_value &= ( ~0x1CF );
printf( "CPSR = %lx\n", cpsr_value );
asm( "msr cpsr, %0\n\t"
: "=r" ( cpsr_value ) );
/* load the VM */
memcpy( ( uint8_t * )android_vm_table[0].loader_start + KERNEL_LOAD_ADDR,
android_vm_table[0].kernel_location,
android_vm_table[0].kernel_size );
putstr( "Loading the Ramdisk...\n" );
memcpy( ( uint8_t * )android_vm_table[0].loader_start + INITRD_LOAD_ADDR,
android_vm_table[0].initrd_location,
android_vm_table[0].ramdisk_size );
putstr( "Copying the BL params...\n" );
bootloader[1] |= 1441 & 0xff;
bootloader[2] |= ( 1441 >> 8 ) & 0xff;
bootloader[5] = KERNEL_ARGS_ADDR + android_vm_table[0].loader_start;
bootloader[6] = KERNEL_LOAD_ADDR + android_vm_table[0].loader_start;
memcpy( ( uint8_t * )android_vm_table[0].loader_start,
bootloader,
sizeof( bootloader ) );
set_kernel_args( android_vm_table[0].loader_start,
RAM_SIZE_FOR_VM,
android_vm_table[0].ramdisk_size,
"" );
putstr( "Finished Loading the first VM...\n" );
/* Give control to the scheduler */
vm_boot = ( boot_fn ) android_vm_table[0].loader_start;
vm_boot( );
while( 1 );
}
/* Instruction printing code for the ARM
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
Free Software Foundation, Inc.
Contributed by Richard Earnshaw ( rwe@pegasus.esprit.ec.org )
Modification by James G. Smith ( jsmith@cygnus.co.uk )
This file is part of libopcodes.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or ( at your option )
any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "dis-asm.h"
struct arm_opcode {
unsigned long value, mask; /* recognise instruction if ( op&mask )==value */
char *assembler; /* how to disassemble this instruction */
};
struct thumb_opcode
{
unsigned short value, mask; /* recognise instruction if ( op&mask )==value */
char * assembler; /* how to disassemble this instruction */
};
/* format of the assembler string :
%% %
%<bitfield>d print the bitfield in decimal
%<bitfield>x print the bitfield in hex
%<bitfield>X print the bitfield as 1 hex digit without leading "0x"
%<bitfield>r print as an ARM register
%<bitfield>f print a floating point constant if >7 else a
floating point register
%<code>y print a single precision VFP reg.
Codes: 0=>Sm, 1=>Sd, 2=>Sn, 3=>multi-list, 4=>Sm pair
%<code>z print a double precision VFP reg
Codes: 0=>Dm, 1=>Dd, 2=>Dn, 3=>multi-list
%c print condition code ( always bits 28-31 )
%P print floating point precision in arithmetic insn
%Q print floating point precision in ldf/stf insn
%R print floating point rounding mode
%<bitnum>'c print specified char iff bit is one
%<bitnum>`c print specified char iff bit is zero
%<bitnum>?ab print a if bit is one else print b
%p print 'p' iff bits 12-15 are 15
%t print 't' iff bit 21 set and bit 24 clear
%o print operand2 ( immediate or register + shift )
%a print address for ldr/str instruction
%s print address for ldr/str halfword/signextend instruction
%b print branch destination
%B print arm BLX( 1 ) destination
%A print address for ldc/stc/ldf/stf instruction
%m print register mask for ldm/stm instruction
%C print the PSR sub type.
%F print the COUNT field of a LFM/SFM instruction.
Thumb specific format options:
%D print Thumb register ( bits 0..2 as high number if bit 7 set )
%S print Thumb register ( bits 3..5 as high number if bit 6 set )
%<bitfield>I print bitfield as a signed decimal
( top bit of range being the sign bit )
%M print Thumb register mask
%N print Thumb register mask ( with LR )
%O print Thumb register mask ( with PC )
%T print Thumb condition code ( always bits 8-11 )
%I print cirrus signed shift immediate: bits 0..3|4..6
%<bitfield>B print Thumb branch destination ( signed displacement )
%<bitfield>W print ( bitfield * 4 ) as a decimal
%<bitfield>H print ( bitfield * 2 ) as a decimal
%<bitfield>a print ( bitfield * 4 ) as a pc-rel offset + decoded symbol
*/
/* Note: There is a partial ordering in this table - it must be searched from
the top to obtain a correct match. */
static struct arm_opcode arm_opcodes[] =
{
/* ARM instructions. */
{0xe1a00000, 0xffffffff, "nop\t\t\t( mov r0, r0 )"},
{0x012FFF10, 0x0ffffff0, "bx%c\t%0-3r"},
{0x00000090, 0x0fe000f0, "mul%c%20's\t%16-19r, %0-3r, %8-11r"},
{0x00200090, 0x0fe000f0, "mla%c%20's\t%16-19r, %0-3r, %8-11r, %12-15r"},
{0x01000090, 0x0fb00ff0, "swp%c%22'b\t%12-15r, %0-3r, [%16-19r]"},
{0x00800090, 0x0fa000f0, "%22?sumull%c%20's\t%12-15r, %16-19r, %0-3r, %8-11r"},
{0x00a00090, 0x0fa000f0, "%22?sumlal%c%20's\t%12-15r, %16-19r, %0-3r, %8-11r"},
/* V5J instruction. */
{0x012fff20, 0x0ffffff0, "bxj%c\t%0-3r"},
/* XScale instructions. */
{0x0e200010, 0x0fff0ff0, "mia%c\tacc0, %0-3r, %12-15r"},
{0x0e280010, 0x0fff0ff0, "miaph%c\tacc0, %0-3r, %12-15r"},
{0x0e2c0010, 0x0ffc0ff0, "mia%17'T%17`B%16'T%16`B%c\tacc0, %0-3r, %12-15r"},
{0x0c400000, 0x0ff00fff, "mar%c\tacc0, %12-15r, %16-19r"},
{0x0c500000, 0x0ff00fff, "mra%c\t%12-15r, %16-19r, acc0"},
{0xf450f000, 0xfc70f000, "pld\t%a"},
/* V5 Instructions. */
{0xe1200070, 0xfff000f0, "bkpt\t0x%16-19X%12-15X%8-11X%0-3X"},
{0xfa000000, 0xfe000000, "blx\t%B"},
{0x012fff30, 0x0ffffff0, "blx%c\t%0-3r"},
{0x016f0f10, 0x0fff0ff0, "clz%c\t%12-15r, %0-3r"},
{0xfc100000, 0xfe100000, "ldc2%22'l\t%8-11d, cr%12-15d, %A"},
{0xfc000000, 0xfe100000, "stc2%22'l\t%8-11d, cr%12-15d, %A"},
{0xfe000000, 0xff000010, "cdp2\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"},
{0xfe000010, 0xff100010, "mcr2\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
{0xfe100010, 0xff100010, "mrc2\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
/* V5E "El Segundo" Instructions. */
{0x000000d0, 0x0e1000f0, "ldr%cd\t%12-15r, %s"},
{0x000000f0, 0x0e1000f0, "str%cd\t%12-15r, %s"},
{0x01000080, 0x0ff000f0, "smlabb%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
{0x010000a0, 0x0ff000f0, "smlatb%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
{0x010000c0, 0x0ff000f0, "smlabt%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
{0x010000e0, 0x0ff000f0, "smlatt%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
{0x01200080, 0x0ff000f0, "smlawb%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
{0x012000c0, 0x0ff000f0, "smlawt%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
{0x01400080, 0x0ff000f0, "smlalbb%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
{0x014000a0, 0x0ff000f0, "smlaltb%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
{0x014000c0, 0x0ff000f0, "smlalbt%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
{0x014000e0, 0x0ff000f0, "smlaltt%c\t%12-15r, %16-19r, %0-3r, %8-11r"},
{0x01600080, 0x0ff0f0f0, "smulbb%c\t%16-19r, %0-3r, %8-11r"},
{0x016000a0, 0x0ff0f0f0, "smultb%c\t%16-19r, %0-3r, %8-11r"},
{0x016000c0, 0x0ff0f0f0, "smulbt%c\t%16-19r, %0-3r, %8-11r"},
{0x016000e0, 0x0ff0f0f0, "smultt%c\t%16-19r, %0-3r, %8-11r"},
{0x012000a0, 0x0ff0f0f0, "smulwb%c\t%16-19r, %0-3r, %8-11r"},
{0x012000e0, 0x0ff0f0f0, "smulwt%c\t%16-19r, %0-3r, %8-11r"},
{0x01000050, 0x0ff00ff0, "qadd%c\t%12-15r, %0-3r, %16-19r"},
{0x01400050, 0x0ff00ff0, "qdadd%c\t%12-15r, %0-3r, %16-19r"},
{0x01200050, 0x0ff00ff0, "qsub%c\t%12-15r, %0-3r, %16-19r"},
{0x01600050, 0x0ff00ff0, "qdsub%c\t%12-15r, %0-3r, %16-19r"},
{0x0c400000, 0x0ff00000, "mcrr%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"},
{0x0c500000, 0x0ff00000, "mrrc%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"},
/* ARM Instructions. */
{0x00000090, 0x0e100090, "str%c%6's%5?hb\t%12-15r, %s"},
{0x00100090, 0x0e100090, "ldr%c%6's%5?hb\t%12-15r, %s"},
{0x00000000, 0x0de00000, "and%c%20's\t%12-15r, %16-19r, %o"},
{0x00200000, 0x0de00000, "eor%c%20's\t%12-15r, %16-19r, %o"},
{0x00400000, 0x0de00000, "sub%c%20's\t%12-15r, %16-19r, %o"},
{0x00600000, 0x0de00000, "rsb%c%20's\t%12-15r, %16-19r, %o"},
{0x00800000, 0x0de00000, "add%c%20's\t%12-15r, %16-19r, %o"},
{0x00a00000, 0x0de00000, "adc%c%20's\t%12-15r, %16-19r, %o"},
{0x00c00000, 0x0de00000, "sbc%c%20's\t%12-15r, %16-19r, %o"},
{0x00e00000, 0x0de00000, "rsc%c%20's\t%12-15r, %16-19r, %o"},
{0x0120f000, 0x0db0f000, "msr%c\t%22?SCPSR%C, %o"},
{0x010f0000, 0x0fbf0fff, "mrs%c\t%12-15r, %22?SCPSR"},
{0x01000000, 0x0de00000, "tst%c%p\t%16-19r, %o"},
{0x01200000, 0x0de00000, "teq%c%p\t%16-19r, %o"},
{0x01400000, 0x0de00000, "cmp%c%p\t%16-19r, %o"},
{0x01600000, 0x0de00000, "cmn%c%p\t%16-19r, %o"},
{0x01800000, 0x0de00000, "orr%c%20's\t%12-15r, %16-19r, %o"},
{0x01a00000, 0x0de00000, "mov%c%20's\t%12-15r, %o"},
{0x01c00000, 0x0de00000, "bic%c%20's\t%12-15r, %16-19r, %o"},
{0x01e00000, 0x0de00000, "mvn%c%20's\t%12-15r, %o"},
{0x04000000, 0x0e100000, "str%c%22'b%t\t%12-15r, %a"},
{0x06000000, 0x0e100ff0, "str%c%22'b%t\t%12-15r, %a"},
{0x04000000, 0x0c100010, "str%c%22'b%t\t%12-15r, %a"},
{0x06000010, 0x0e000010, "undefined"},
{0x04100000, 0x0c100000, "ldr%c%22'b%t\t%12-15r, %a"},
{0x08000000, 0x0e100000, "stm%c%23?id%24?ba\t%16-19r%21'!, %m%22'^"},
{0x08100000, 0x0e100000, "ldm%c%23?id%24?ba\t%16-19r%21'!, %m%22'^"},
{0x0a000000, 0x0e000000, "b%24'l%c\t%b"},
{0x0f000000, 0x0f000000, "swi%c\t%0-23x"},
/* Floating point coprocessor ( FPA ) instructions */
{0x0e000100, 0x0ff08f10, "adf%c%P%R\t%12-14f, %16-18f, %0-3f"},
{0x0e100100, 0x0ff08f10, "muf%c%P%R\t%12-14f, %16-18f, %0-3f"},
{0x0e200100, 0x0ff08f10, "suf%c%P%R\t%12-14f, %16-18f, %0-3f"},
{0x0e300100, 0x0ff08f10, "rsf%c%P%R\t%12-14f, %16-18f, %0-3f"},
{0x0e400100, 0x0ff08f10, "dvf%c%P%R\t%12-14f, %16-18f, %0-3f"},
{0x0e500100, 0x0ff08f10, "rdf%c%P%R\t%12-14f, %16-18f, %0-3f"},
{0x0e600100, 0x0ff08f10, "pow%c%P%R\t%12-14f, %16-18f, %0-3f"},
{0x0e700100, 0x0ff08f10, "rpw%c%P%R\t%12-14f, %16-18f, %0-3f"},
{0x0e800100, 0x0ff08f10, "rmf%c%P%R\t%12-14f, %16-18f, %0-3f"},
{0x0e900100, 0x0ff08f10, "fml%c%P%R\t%12-14f, %16-18f, %0-3f"},
{0x0ea00100, 0x0ff08f10, "fdv%c%P%R\t%12-14f, %16-18f, %0-3f"},
{0x0eb00100, 0x0ff08f10, "frd%c%P%R\t%12-14f, %16-18f, %0-3f"},
{0x0ec00100, 0x0ff08f10, "pol%c%P%R\t%12-14f, %16-18f, %0-3f"},
{0x0e008100, 0x0ff08f10, "mvf%c%P%R\t%12-14f, %0-3f"},
{0x0e108100, 0x0ff08f10, "mnf%c%P%R\t%12-14f, %0-3f"},
{0x0e208100, 0x0ff08f10, "abs%c%P%R\t%12-14f, %0-3f"},
{0x0e308100, 0x0ff08f10, "rnd%c%P%R\t%12-14f, %0-3f"},
{0x0e408100, 0x0ff08f10, "sqt%c%P%R\t%12-14f, %0-3f"},
{0x0e508100, 0x0ff08f10, "log%c%P%R\t%12-14f, %0-3f"},
{0x0e608100, 0x0ff08f10, "lgn%c%P%R\t%12-14f, %0-3f"},
{0x0e708100, 0x0ff08f10, "exp%c%P%R\t%12-14f, %0-3f"},
{0x0e808100, 0x0ff08f10, "sin%c%P%R\t%12-14f, %0-3f"},
{0x0e908100, 0x0ff08f10, "cos%c%P%R\t%12-14f, %0-3f"},
{0x0ea08100, 0x0ff08f10, "tan%c%P%R\t%12-14f, %0-3f"},
{0x0eb08100, 0x0ff08f10, "asn%c%P%R\t%12-14f, %0-3f"},
{0x0ec08100, 0x0ff08f10, "acs%c%P%R\t%12-14f, %0-3f"},
{0x0ed08100, 0x0ff08f10, "atn%c%P%R\t%12-14f, %0-3f"},
{0x0ee08100, 0x0ff08f10, "urd%c%P%R\t%12-14f, %0-3f"},
{0x0ef08100, 0x0ff08f10, "nrm%c%P%R\t%12-14f, %0-3f"},
{0x0e000110, 0x0ff00f1f, "flt%c%P%R\t%16-18f, %12-15r"},
{0x0e100110, 0x0fff0f98, "fix%c%R\t%12-15r, %0-2f"},
{0x0e200110, 0x0fff0fff, "wfs%c\t%12-15r"},
{0x0e300110, 0x0fff0fff, "rfs%c\t%12-15r"},
{0x0e400110, 0x0fff0fff, "wfc%c\t%12-15r"},
{0x0e500110, 0x0fff0fff, "rfc%c\t%12-15r"},
{0x0e90f110, 0x0ff8fff0, "cmf%c\t%16-18f, %0-3f"},
{0x0eb0f110, 0x0ff8fff0, "cnf%c\t%16-18f, %0-3f"},
{0x0ed0f110, 0x0ff8fff0, "cmfe%c\t%16-18f, %0-3f"},
{0x0ef0f110, 0x0ff8fff0, "cnfe%c\t%16-18f, %0-3f"},
{0x0c000100, 0x0e100f00, "stf%c%Q\t%12-14f, %A"},
{0x0c100100, 0x0e100f00, "ldf%c%Q\t%12-14f, %A"},
{0x0c000200, 0x0e100f00, "sfm%c\t%12-14f, %F, %A"},
{0x0c100200, 0x0e100f00, "lfm%c\t%12-14f, %F, %A"},
/* Floating point coprocessor ( VFP ) instructions */
{0x0eb00bc0, 0x0fff0ff0, "fabsd%c\t%1z, %0z"},
{0x0eb00ac0, 0x0fbf0fd0, "fabss%c\t%1y, %0y"},
{0x0e300b00, 0x0ff00ff0, "faddd%c\t%1z, %2z, %0z"},
{0x0e300a00, 0x0fb00f50, "fadds%c\t%1y, %2y, %1y"},
{0x0eb40b40, 0x0fff0f70, "fcmp%7'ed%c\t%1z, %0z"},
{0x0eb40a40, 0x0fbf0f50, "fcmp%7'es%c\t%1y, %0y"},
{0x0eb50b40, 0x0fff0f70, "fcmp%7'ezd%c\t%1z"},
{0x0eb50a40, 0x0fbf0f70, "fcmp%7'ezs%c\t%1y"},
{0x0eb00b40, 0x0fff0ff0, "fcpyd%c\t%1z, %0z"},
{0x0eb00a40, 0x0fbf0fd0, "fcpys%c\t%1y, %0y"},
{0x0eb70ac0, 0x0fff0fd0, "fcvtds%c\t%1z, %0y"},
{0x0eb70bc0, 0x0fbf0ff0, "fcvtsd%c\t%1y, %0z"},
{0x0e800b00, 0x0ff00ff0, "fdivd%c\t%1z, %2z, %0z"},
{0x0e800a00, 0x0fb00f50, "fdivs%c\t%1y, %2y, %0y"},
{0x0d100b00, 0x0f700f00, "fldd%c\t%1z, %A"},
{0x0c900b00, 0x0fd00f00, "fldmia%0?xd%c\t%16-19r%21'!, %3z"},
{0x0d300b00, 0x0ff00f00, "fldmdb%0?xd%c\t%16-19r!, %3z"},
{0x0d100a00, 0x0f300f00, "flds%c\t%1y, %A"},
{0x0c900a00, 0x0f900f00, "fldmias%c\t%16-19r%21'!, %3y"},
{0x0d300a00, 0x0fb00f00, "fldmdbs%c\t%16-19r!, %3y"},
{0x0e000b00, 0x0ff00ff0, "fmacd%c\t%1z, %2z, %0z"},
{0x0e000a00, 0x0fb00f50, "fmacs%c\t%1y, %2y, %0y"},
{0x0e200b10, 0x0ff00fff, "fmdhr%c\t%2z, %12-15r"},
{0x0e000b10, 0x0ff00fff, "fmdlr%c\t%2z, %12-15r"},
{0x0c400b10, 0x0ff00ff0, "fmdrr%c\t%0z, %12-15r, %16-19r"},
{0x0e300b10, 0x0ff00fff, "fmrdh%c\t%12-15r, %2z"},
{0x0e100b10, 0x0ff00fff, "fmrdl%c\t%12-15r, %2z"},
{0x0c500b10, 0x0ff00ff0, "fmrrd%c\t%12-15r, %16-19r, %0z"},
{0x0c500a10, 0x0ff00fd0, "fmrrs%c\t%12-15r, %16-19r, %4y"},
{0x0e100a10, 0x0ff00f7f, "fmrs%c\t%12-15r, %2y"},
{0x0ef1fa10, 0x0fffffff, "fmstat%c"},
{0x0ef00a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpsid"},
{0x0ef10a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpscr"},
{0x0ef80a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpexc"},
{0x0ef90a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst\t@ Impl def"},
{0x0efa0a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst2\t@ Impl def"},
{0x0ef00a10, 0x0ff00fff, "fmrx%c\t%12-15r, <impl def 0x%16-19x>"},
{0x0e100b00, 0x0ff00ff0, "fmscd%c\t%1z, %2z, %0z"},
{0x0e100a00, 0x0fb00f50, "fmscs%c\t%1y, %2y, %0y"},
{0x0e000a10, 0x0ff00f7f, "fmsr%c\t%2y, %12-15r"},
{0x0c400a10, 0x0ff00fd0, "fmsrr%c\t%12-15r, %16-19r, %4y"},
{0x0e200b00, 0x0ff00ff0, "fmuld%c\t%1z, %2z, %0z"},
{0x0e200a00, 0x0fb00f50, "fmuls%c\t%1y, %2y, %0y"},
{0x0ee00a10, 0x0fff0fff, "fmxr%c\tfpsid, %12-15r"},
{0x0ee10a10, 0x0fff0fff, "fmxr%c\tfpscr, %12-15r"},
{0x0ee80a10, 0x0fff0fff, "fmxr%c\tfpexc, %12-15r"},
{0x0ee90a10, 0x0fff0fff, "fmxr%c\tfpinst, %12-15r\t@ Impl def"},
{0x0eea0a10, 0x0fff0fff, "fmxr%c\tfpinst2, %12-15r\t@ Impl def"},
{0x0ee00a10, 0x0ff00fff, "fmxr%c\t<impl def 0x%16-19x>, %12-15r"},
{0x0eb10b40, 0x0fff0ff0, "fnegd%c\t%1z, %0z"},
{0x0eb10a40, 0x0fbf0fd0, "fnegs%c\t%1y, %0y"},
{0x0e000b40, 0x0ff00ff0, "fnmacd%c\t%1z, %2z, %0z"},
{0x0e000a40, 0x0fb00f50, "fnmacs%c\t%1y, %2y, %0y"},
{0x0e100b40, 0x0ff00ff0, "fnmscd%c\t%1z, %2z, %0z"},
{0x0e100a40, 0x0fb00f50, "fnmscs%c\t%1y, %2y, %0y"},
{0x0e200b40, 0x0ff00ff0, "fnmuld%c\t%1z, %2z, %0z"},
{0x0e200a40, 0x0fb00f50, "fnmuls%c\t%1y, %2y, %0y"},
{0x0eb80bc0, 0x0fff0fd0, "fsitod%c\t%1z, %0y"},
{0x0eb80ac0, 0x0fbf0fd0, "fsitos%c\t%1y, %0y"},
{0x0eb10bc0, 0x0fff0ff0, "fsqrtd%c\t%1z, %0z"},
{0x0eb10ac0, 0x0fbf0fd0, "fsqrts%c\t%1y, %0y"},
{0x0d000b00, 0x0f700f00, "fstd%c\t%1z, %A"},
{0x0c800b00, 0x0fd00f00, "fstmia%0?xd%c\t%16-19r%21'!, %3z"},
{0x0d200b00, 0x0ff00f00, "fstmdb%0?xd%c\t%16-19r!, %3z"},
{0x0d000a00, 0x0f300f00, "fsts%c\t%1y, %A"},
{0x0c800a00, 0x0f900f00, "fstmias%c\t%16-19r%21'!, %3y"},
{0x0d200a00, 0x0fb00f00, "fstmdbs%c\t%16-19r!, %3y"},
{0x0e300b40, 0x0ff00ff0, "fsubd%c\t%1z, %2z, %0z"},
{0x0e300a40, 0x0fb00f50, "fsubs%c\t%1y, %2y, %0y"},
{0x0ebc0b40, 0x0fbe0f70, "fto%16?sui%7'zd%c\t%1y, %0z"},
{0x0ebc0a40, 0x0fbe0f50, "fto%16?sui%7'zs%c\t%1y, %0y"},
{0x0eb80b40, 0x0fff0fd0, "fuitod%c\t%1z, %0y"},
{0x0eb80a40, 0x0fbf0fd0, "fuitos%c\t%1y, %0y"},
/* Cirrus coprocessor instructions. */
{0x0d100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"},
{0x0c100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"},
{0x0d500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"},
{0x0c500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"},
{0x0d100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"},
{0x0c100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"},
{0x0d500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"},
{0x0c500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"},
{0x0d000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"},
{0x0c000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"},
{0x0d400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"},
{0x0c400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"},
{0x0d000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"},
{0x0c000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"},
{0x0d400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"},
{0x0c400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"},
{0x0e000450, 0x0ff00ff0, "cfmvsr%c\tmvf%16-19d, %12-15r"},
{0x0e100450, 0x0ff00ff0, "cfmvrs%c\t%12-15r, mvf%16-19d"},
{0x0e000410, 0x0ff00ff0, "cfmvdlr%c\tmvd%16-19d, %12-15r"},
{0x0e100410, 0x0ff00ff0, "cfmvrdl%c\t%12-15r, mvd%16-19d"},
{0x0e000430, 0x0ff00ff0, "cfmvdhr%c\tmvd%16-19d, %12-15r"},
{0x0e100430, 0x0ff00fff, "cfmvrdh%c\t%12-15r, mvd%16-19d"},
{0x0e000510, 0x0ff00fff, "cfmv64lr%c\tmvdx%16-19d, %12-15r"},
{0x0e100510, 0x0ff00fff, "cfmvr64l%c\t%12-15r, mvdx%16-19d"},
{0x0e000530, 0x0ff00fff, "cfmv64hr%c\tmvdx%16-19d, %12-15r"},
{0x0e100530, 0x0ff00fff, "cfmvr64h%c\t%12-15r, mvdx%16-19d"},
{0x0e100610, 0x0ff0fff0, "cfmval32%c\tmvax%0-3d, mvfx%16-19d"},
{0x0e000610, 0x0ff0fff0, "cfmv32al%c\tmvfx%0-3d, mvax%16-19d"},
{0x0e100630, 0x0ff0fff0, "cfmvam32%c\tmvax%0-3d, mvfx%16-19d"},
{0x0e000630, 0x0ff0fff0, "cfmv32am%c\tmvfx%0-3d, mvax%16-19d"},
{0x0e100650, 0x0ff0fff0, "cfmvah32%c\tmvax%0-3d, mvfx%16-19d"},
{0x0e000650, 0x0ff0fff0, "cfmv32ah%c\tmvfx%0-3d, mvax%16-19d"},
{0x0e000670, 0x0ff0fff0, "cfmv32a%c\tmvfx%0-3d, mvax%16-19d"},
{0x0e100670, 0x0ff0fff0, "cfmva32%c\tmvax%0-3d, mvfx%16-19d"},
{0x0e000690, 0x0ff0fff0, "cfmv64a%c\tmvdx%0-3d, mvax%16-19d"},
{0x0e100690, 0x0ff0fff0, "cfmva64%c\tmvax%0-3d, mvdx%16-19d"},
{0x0e1006b0, 0x0ff0fff0, "cfmvsc32%c\tdspsc, mvfx%16-19d"},
{0x0e0006b0, 0x0ff0fff0, "cfmv32sc%c\tmvfx%0-3d, dspsc"},
{0x0e000400, 0x0ff00fff, "cfcpys%c\tmvf%12-15d, mvf%16-19d"},
{0x0e000420, 0x0ff00fff, "cfcpyd%c\tmvd%12-15d, mvd%16-19d"},
{0x0e000460, 0x0ff00fff, "cfcvtsd%c\tmvd%12-15d, mvf%16-19d"},
{0x0e000440, 0x0ff00fff, "cfcvtds%c\tmvf%12-15d, mvd%16-19d"},
{0x0e000480, 0x0ff00fff, "cfcvt32s%c\tmvf%12-15d, mvfx%16-19d"},
{0x0e0004a0, 0x0ff00fff, "cfcvt32d%c\tmvd%12-15d, mvfx%16-19d"},
{0x0e0004c0, 0x0ff00fff, "cfcvt64s%c\tmvf%12-15d, mvdx%16-19d"},
{0x0e0004e0, 0x0ff00fff, "cfcvt64d%c\tmvd%12-15d, mvdx%16-19d"},
{0x0e100580, 0x0ff00fff, "cfcvts32%c\tmvfx%12-15d, mvf%16-19d"},
{0x0e1005a0, 0x0ff00fff, "cfcvtd32%c\tmvfx%12-15d, mvd%16-19d"},
{0x0e1005c0, 0x0ff00fff, "cftruncs32%c\tmvfx%12-15d, mvf%16-19d"},
{0x0e1005e0, 0x0ff00fff, "cftruncd32%c\tmvfx%12-15d, mvd%16-19d"},
{0x0e000550, 0x0ff00ff0, "cfrshl32%c\tmvfx%16-19d, mvfx%0-3d, %12-15r"},
{0x0e000570, 0x0ff00ff0, "cfrshl64%c\tmvdx%16-19d, mvdx%0-3d, %12-15r"},
{0x0e000500, 0x0ff00f00, "cfsh32%c\tmvfx%12-15d, mvfx%16-19d, #%I"},
{0x0e200500, 0x0ff00f00, "cfsh64%c\tmvdx%12-15d, mvdx%16-19d, #%I"},
{0x0e100490, 0x0ff00ff0, "cfcmps%c\t%12-15r, mvf%16-19d, mvf%0-3d"},
{0x0e1004b0, 0x0ff00ff0, "cfcmpd%c\t%12-15r, mvd%16-19d, mvd%0-3d"},
{0x0e100590, 0x0ff00ff0, "cfcmp32%c\t%12-15r, mvfx%16-19d, mvfx%0-3d"},
{0x0e1005b0, 0x0ff00ff0, "cfcmp64%c\t%12-15r, mvdx%16-19d, mvdx%0-3d"},
{0x0e300400, 0x0ff00fff, "cfabss%c\tmvf%12-15d, mvf%16-19d"},
{0x0e300420, 0x0ff00fff, "cfabsd%c\tmvd%12-15d, mvd%16-19d"},
{0x0e300440, 0x0ff00fff, "cfnegs%c\tmvf%12-15d, mvf%16-19d"},
{0x0e300460, 0x0ff00fff, "cfnegd%c\tmvd%12-15d, mvd%16-19d"},
{0x0e300480, 0x0ff00ff0, "cfadds%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"},
{0x0e3004a0, 0x0ff00ff0, "cfaddd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"},
{0x0e3004c0, 0x0ff00ff0, "cfsubs%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"},
{0x0e3004e0, 0x0ff00ff0, "cfsubd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"},
{0x0e100400, 0x0ff00ff0, "cfmuls%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"},
{0x0e100420, 0x0ff00ff0, "cfmuld%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"},
{0x0e300500, 0x0ff00fff, "cfabs32%c\tmvfx%12-15d, mvfx%16-19d"},
{0x0e300520, 0x0ff00fff, "cfabs64%c\tmvdx%12-15d, mvdx%16-19d"},
{0x0e300540, 0x0ff00fff, "cfneg32%c\tmvfx%12-15d, mvfx%16-19d"},
{0x0e300560, 0x0ff00fff, "cfneg64%c\tmvdx%12-15d, mvdx%16-19d"},
{0x0e300580, 0x0ff00ff0, "cfadd32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
{0x0e3005a0, 0x0ff00ff0, "cfadd64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"},
{0x0e3005c0, 0x0ff00ff0, "cfsub32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
{0x0e3005e0, 0x0ff00ff0, "cfsub64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"},
{0x0e100500, 0x0ff00ff0, "cfmul32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
{0x0e100520, 0x0ff00ff0, "cfmul64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"},
{0x0e100540, 0x0ff00ff0, "cfmac32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
{0x0e100560, 0x0ff00ff0, "cfmsc32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
{0x0e000600, 0x0ff00f00, "cfmadd32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
{0x0e100600, 0x0ff00f00, "cfmsub32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"},
{0x0e200600, 0x0ff00f00, "cfmadda32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"},
{0x0e300600, 0x0ff00f00, "cfmsuba32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"},
/* Generic coprocessor instructions */
{0x0e000000, 0x0f000010, "cdp%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"},
{0x0e100010, 0x0f100010, "mrc%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
{0x0e000010, 0x0f100010, "mcr%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
{0x0c000000, 0x0e100000, "stc%c%22'l\t%8-11d, cr%12-15d, %A"},
{0x0c100000, 0x0e100000, "ldc%c%22'l\t%8-11d, cr%12-15d, %A"},
/* The rest. */
{0x00000000, 0x00000000, "undefined instruction %0-31x"},
{0x00000000, 0x00000000, 0}
};
#define BDISP( x ) ( ( ( ( x ) & 0xffffff ) ^ 0x800000 ) - 0x800000 ) /* 26 bit */
static struct thumb_opcode thumb_opcodes[] =
{
/* Thumb instructions. */
/* ARM V5 ISA extends Thumb. */
{0xbe00, 0xff00, "bkpt\t%0-7x"},
{0x4780, 0xff87, "blx\t%3-6r"}, /* note: 4 bit register number. */
/* Note: this is BLX( 2 ). BLX( 1 ) is done in arm-dis.c/print_insn_thumb( )
as an extension of the special processing there for Thumb BL.
BL and BLX( 1 ) involve 2 successive 16-bit instructions, which must
always appear together in the correct order. So, the empty
string is put in this table, and the string interpreter takes <empty>
to mean it has a pair of BL-ish instructions. */
{0x46C0, 0xFFFF, "nop\t\t\t( mov r8, r8 )"},
/* Format 5 instructions do not update the PSR. */
{0x1C00, 0xFFC0, "mov\t%0-2r, %3-5r\t\t( add %0-2r, %3-5r, #%6-8d )"},
/* Format 4. */
{0x4000, 0xFFC0, "and\t%0-2r, %3-5r"},
{0x4040, 0xFFC0, "eor\t%0-2r, %3-5r"},
{0x4080, 0xFFC0, "lsl\t%0-2r, %3-5r"},
{0x40C0, 0xFFC0, "lsr\t%0-2r, %3-5r"},
{0x4100, 0xFFC0, "asr\t%0-2r, %3-5r"},
{0x4140, 0xFFC0, "adc\t%0-2r, %3-5r"},
{0x4180, 0xFFC0, "sbc\t%0-2r, %3-5r"},
{0x41C0, 0xFFC0, "ror\t%0-2r, %3-5r"},
{0x4200, 0xFFC0, "tst\t%0-2r, %3-5r"},
{0x4240, 0xFFC0, "neg\t%0-2r, %3-5r"},
{0x4280, 0xFFC0, "cmp\t%0-2r, %3-5r"},
{0x42C0, 0xFFC0, "cmn\t%0-2r, %3-5r"},
{0x4300, 0xFFC0, "orr\t%0-2r, %3-5r"},
{0x4340, 0xFFC0, "mul\t%0-2r, %3-5r"},
{0x4380, 0xFFC0, "bic\t%0-2r, %3-5r"},
{0x43C0, 0xFFC0, "mvn\t%0-2r, %3-5r"},
/* format 13 */
{0xB000, 0xFF80, "add\tsp, #%0-6W"},
{0xB080, 0xFF80, "sub\tsp, #%0-6W"},
/* format 5 */
{0x4700, 0xFF80, "bx\t%S"},
{0x4400, 0xFF00, "add\t%D, %S"},
{0x4500, 0xFF00, "cmp\t%D, %S"},
{0x4600, 0xFF00, "mov\t%D, %S"},
/* format 14 */
{0xB400, 0xFE00, "push\t%N"},
{0xBC00, 0xFE00, "pop\t%O"},
/* format 2 */
{0x1800, 0xFE00, "add\t%0-2r, %3-5r, %6-8r"},
{0x1A00, 0xFE00, "sub\t%0-2r, %3-5r, %6-8r"},
{0x1C00, 0xFE00, "add\t%0-2r, %3-5r, #%6-8d"},
{0x1E00, 0xFE00, "sub\t%0-2r, %3-5r, #%6-8d"},
/* format 8 */
{0x5200, 0xFE00, "strh\t%0-2r, [%3-5r, %6-8r]"},
{0x5A00, 0xFE00, "ldrh\t%0-2r, [%3-5r, %6-8r]"},
{0x5600, 0xF600, "ldrs%11?hb\t%0-2r, [%3-5r, %6-8r]"},
/* format 7 */
{0x5000, 0xFA00, "str%10'b\t%0-2r, [%3-5r, %6-8r]"},
{0x5800, 0xFA00, "ldr%10'b\t%0-2r, [%3-5r, %6-8r]"},
/* format 1 */
{0x0000, 0xF800, "lsl\t%0-2r, %3-5r, #%6-10d"},
{0x0800, 0xF800, "lsr\t%0-2r, %3-5r, #%6-10d"},
{0x1000, 0xF800, "asr\t%0-2r, %3-5r, #%6-10d"},
/* format 3 */
{0x2000, 0xF800, "mov\t%8-10r, #%0-7d"},
{0x2800, 0xF800, "cmp\t%8-10r, #%0-7d"},
{0x3000, 0xF800, "add\t%8-10r, #%0-7d"},
{0x3800, 0xF800, "sub\t%8-10r, #%0-7d"},
/* format 6 */
{0x4800, 0xF800, "ldr\t%8-10r, [pc, #%0-7W]\t( %0-7a )"}, /* TODO: Disassemble PC relative "LDR rD, =<symbolic>" */
/* format 9 */
{0x6000, 0xF800, "str\t%0-2r, [%3-5r, #%6-10W]"},
{0x6800, 0xF800, "ldr\t%0-2r, [%3-5r, #%6-10W]"},
{0x7000, 0xF800, "strb\t%0-2r, [%3-5r, #%6-10d]"},
{0x7800, 0xF800, "ldrb\t%0-2r, [%3-5r, #%6-10d]"},
/* format 10 */
{0x8000, 0xF800, "strh\t%0-2r, [%3-5r, #%6-10H]"},
{0x8800, 0xF800, "ldrh\t%0-2r, [%3-5r, #%6-10H]"},
/* format 11 */
{0x9000, 0xF800, "str\t%8-10r, [sp, #%0-7W]"},
{0x9800, 0xF800, "ldr\t%8-10r, [sp, #%0-7W]"},
/* format 12 */
{0xA000, 0xF800, "add\t%8-10r, pc, #%0-7W\t( adr %8-10r, %0-7a )"},
{0xA800, 0xF800, "add\t%8-10r, sp, #%0-7W"},
/* format 15 */
{0xC000, 0xF800, "stmia\t%8-10r!, %M"},
{0xC800, 0xF800, "ldmia\t%8-10r!, %M"},
/* format 18 */
{0xE000, 0xF800, "b\t%0-10B"},
{0xE800, 0xF800, "undefined"},
/* format 19 */
{0xF000, 0xF800, ""}, /* special processing required in disassembler */
{0xF800, 0xF800, "second half of BL instruction %0-15x"},
/* format 16 */
{0xD000, 0xFF00, "beq\t%0-7B"},
{0xD100, 0xFF00, "bne\t%0-7B"},
{0xD200, 0xFF00, "bcs\t%0-7B"},
{0xD300, 0xFF00, "bcc\t%0-7B"},
{0xD400, 0xFF00, "bmi\t%0-7B"},
{0xD500, 0xFF00, "bpl\t%0-7B"},
{0xD600, 0xFF00, "bvs\t%0-7B"},
{0xD700, 0xFF00, "bvc\t%0-7B"},
{0xD800, 0xFF00, "bhi\t%0-7B"},
{0xD900, 0xFF00, "bls\t%0-7B"},
{0xDA00, 0xFF00, "bge\t%0-7B"},
{0xDB00, 0xFF00, "blt\t%0-7B"},
{0xDC00, 0xFF00, "bgt\t%0-7B"},
{0xDD00, 0xFF00, "ble\t%0-7B"},
/* format 17 */
{0xDE00, 0xFF00, "bal\t%0-7B"},
{0xDF00, 0xFF00, "swi\t%0-7d"},
/* format 9 */
{0x6000, 0xF800, "str\t%0-2r, [%3-5r, #%6-10W]"},
{0x6800, 0xF800, "ldr\t%0-2r, [%3-5r, #%6-10W]"},
{0x7000, 0xF800, "strb\t%0-2r, [%3-5r, #%6-10d]"},
{0x7800, 0xF800, "ldrb\t%0-2r, [%3-5r, #%6-10d]"},
/* the rest */
{0x0000, 0x0000, "undefined instruction %0-15x"},
{0x0000, 0x0000, 0}
};
#define BDISP23( x ) ( ( ( ( ( ( x ) & 0x07ff ) << 11 ) | ( ( ( x ) & 0x07ff0000 ) >> 16 ) ) \
^ 0x200000 ) - 0x200000 ) /* 23bit */
#ifndef streq
#define streq( a, b ) ( strcmp ( ( a ), ( b ) ) == 0 )
#endif
#ifndef strneq
#define strneq( a, b, n ) ( strncmp ( ( a ), ( b ), ( n ) ) == 0 )
#endif
#ifndef NUM_ELEM
#define NUM_ELEM( a ) ( sizeof ( a ) / sizeof ( a )[0] )
#endif
static char * arm_conditional[] =
{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
"hi", "ls", "ge", "lt", "gt", "le", "", "nv"};
typedef struct
{
const char * name;
const char * description;
const char * reg_names[16];
}
arm_regname;
static arm_regname regnames[] =
{
{ "raw" , "Select raw register names",
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}},
{ "gcc", "Select register names used by GCC",
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }},
{ "std", "Select register names used in ARM's ISA documentation",
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }},
{ "apcs", "Select register names used in the APCS",
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }},
{ "atpcs", "Select register names used in the ATPCS",
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }},
{ "special-atpcs", "Select special register names used in the ATPCS",
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }}
};
/* Default to STD register name set. */
static unsigned int regname_selected = 2;
#define NUM_ARM_REGNAMES NUM_ELEM ( regnames )
#define arm_regnames regnames[regname_selected].reg_names
static boolean force_thumb = false;
static char * arm_fp_const[] =
{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"};
static char * arm_shift[] =
{"lsl", "lsr", "asr", "ror"};
/* Forward declarations. */
static void arm_decode_shift PARAMS ( ( long, fprintf_ftype, void * ) );
static int print_insn_arm1 PARAMS ( ( bfd_vma, struct disassemble_info *, long ) );
static int print_insn_thumb PARAMS ( ( bfd_vma, struct disassemble_info *, long ) );
581 static void parse_disassembler_options PARAMS ( ( char * ) );
582 int get_arm_regname_num_options ( void );
583 int set_arm_regname_option ( int option );
int get_arm_regnames ( int option, const char **setname,
const char **setdescription,
const char ***register_names );
/* Functions. */
589 int
get_arm_regname_num_options ( )
{
return NUM_ARM_REGNAMES;
}
595 int
set_arm_regname_option ( option )
int option;
{
int old = regname_selected;
regname_selected = option;
return old;
}
int
get_arm_regnames ( option, setname, setdescription, register_names )
int option;
const char **setname;
const char **setdescription;
const char ***register_names;
{
*setname = regnames[option].name;
*setdescription = regnames[option].description;
*register_names = regnames[option].reg_names;
return 16;
}
static void
arm_decode_shift ( given, func, stream )
long given;
fprintf_ftype func;
void * stream;
{
func ( stream, "%s", arm_regnames[given & 0xf] );
if ( ( given & 0xff0 ) != 0 )
{
if ( ( given & 0x10 ) == 0 )
{
int amount = ( given & 0xf80 ) >> 7;
int shift = ( given & 0x60 ) >> 5;
if ( amount == 0 )
{
if ( shift == 3 )
{
func ( stream, ", rrx" );
return;
}
amount = 32;
}
func ( stream, ", %s #%d", arm_shift[shift], amount );
}
else
func ( stream, ", %s %s", arm_shift[( given & 0x60 ) >> 5],
arm_regnames[( given & 0xf00 ) >> 8] );
}
}
/* Print one instruction from PC on INFO->STREAM.
Return the size of the instruction ( always 4 on ARM ). */
static int
print_insn_arm1 ( pc, info, given )
bfd_vma pc;
struct disassemble_info * info;
long given;
{
struct arm_opcode * insn;
void * stream = info->stream;
fprintf_ftype func = info->fprintf_func;
for ( insn = arm_opcodes; insn->assembler; insn++ )
{
if ( ( given & insn->mask ) == insn->value )
{
char * c;
for ( c = insn->assembler; *c; c++ )
{
if ( *c == '%' )
{
switch ( *++c )
{
case '%':
func ( stream, "%%" );
break;
case 'a':
if ( ( ( given & 0x000f0000 ) == 0x000f0000 )
&& ( ( given & 0x02000000 ) == 0 ) )
{
int offset = given & 0xfff;
func ( stream, "[pc" );
if ( given & 0x01000000 )
{
if ( ( given & 0x00800000 ) == 0 )
offset = - offset;
/* Pre-indexed. */
func ( stream, ", #%d]", offset );
offset += pc + 8;
/* Cope with the possibility of write-back
being used. Probably a very dangerous thing
for the programmer to do, but who are we to
argue ? */
if ( given & 0x00200000 )
func ( stream, "!" );
}
else
{
/* Post indexed. */
func ( stream, "], #%d", offset );
/* ie ignore the offset. */
offset = pc + 8;
}
func ( stream, "\t; " );
info->print_address_func ( offset, info );
}
else
{
func ( stream, "[%s",
arm_regnames[( given >> 16 ) & 0xf] );
if ( ( given & 0x01000000 ) != 0 )
{
if ( ( given & 0x02000000 ) == 0 )
{
int offset = given & 0xfff;
if ( offset )
func ( stream, ", %s#%d",
( ( ( given & 0x00800000 ) == 0 )
? "-" : "" ), offset );
}
else
{
func ( stream, ", %s",
( ( ( given & 0x00800000 ) == 0 )
? "-" : "" ) );
arm_decode_shift ( given, func, stream );
}
func ( stream, "]%s",
( ( given & 0x00200000 ) != 0 ) ? "!" : "" );
}
else
{
if ( ( given & 0x02000000 ) == 0 )
{
int offset = given & 0xfff;
if ( offset )
func ( stream, "], %s#%d",
( ( ( given & 0x00800000 ) == 0 )
? "-" : "" ), offset );
else
func ( stream, "]" );
}
else
{
func ( stream, "], %s",
( ( ( given & 0x00800000 ) == 0 )
? "-" : "" ) );
arm_decode_shift ( given, func, stream );
}
}
}
break;
case 's':
if ( ( given & 0x004f0000 ) == 0x004f0000 )
{
/* PC relative with immediate offset. */
int offset = ( ( given & 0xf00 ) >> 4 ) | ( given & 0xf );
if ( ( given & 0x00800000 ) == 0 )
offset = -offset;
func ( stream, "[pc, #%d]\t; ", offset );
( *info->print_address_func )
( offset + pc + 8, info );
}
else
{
func ( stream, "[%s",
arm_regnames[( given >> 16 ) & 0xf] );
if ( ( given & 0x01000000 ) != 0 )
{
/* Pre-indexed. */
if ( ( given & 0x00400000 ) == 0x00400000 )
{
/* Immediate. */
int offset = ( ( given & 0xf00 ) >> 4 ) | ( given & 0xf );
if ( offset )
func ( stream, ", %s#%d",
( ( ( given & 0x00800000 ) == 0 )
? "-" : "" ), offset );
}
else
{
/* Register. */
func ( stream, ", %s%s",
( ( ( given & 0x00800000 ) == 0 )
? "-" : "" ),
arm_regnames[given & 0xf] );
}
func ( stream, "]%s",
( ( given & 0x00200000 ) != 0 ) ? "!" : "" );
}
else
{
/* Post-indexed. */
if ( ( given & 0x00400000 ) == 0x00400000 )
{
/* Immediate. */
int offset = ( ( given & 0xf00 ) >> 4 ) | ( given & 0xf );
if ( offset )
func ( stream, "], %s#%d",
( ( ( given & 0x00800000 ) == 0 )
? "-" : "" ), offset );
else
func ( stream, "]" );
}
else
{
/* Register. */
func ( stream, "], %s%s",
( ( ( given & 0x00800000 ) == 0 )
? "-" : "" ),
arm_regnames[given & 0xf] );
}
}
}
break;
case 'b':
( *info->print_address_func )
( BDISP ( given ) * 4 + pc + 8, info );
break;
case 'c':
func ( stream, "%s",
arm_conditional [( given >> 28 ) & 0xf] );
break;
case 'm':
{
int started = 0;
int reg;
func ( stream, "{" );
for ( reg = 0; reg < 16; reg++ )
if ( ( given & ( 1 << reg ) ) != 0 )
{
if ( started )
func ( stream, ", " );
started = 1;
func ( stream, "%s", arm_regnames[reg] );
}
func ( stream, "}" );
}
break;
case 'o':
if ( ( given & 0x02000000 ) != 0 )
{
int rotate = ( given & 0xf00 ) >> 7;
int immed = ( given & 0xff );
immed = ( ( ( immed << ( 32 - rotate ) )
| ( immed >> rotate ) ) & 0xffffffff );
func ( stream, "#%d\t; 0x%x", immed, immed );
}
else
arm_decode_shift ( given, func, stream );
break;
case 'p':
if ( ( given & 0x0000f000 ) == 0x0000f000 )
func ( stream, "p" );
break;
case 't':
if ( ( given & 0x01200000 ) == 0x00200000 )
func ( stream, "t" );
break;
case 'A':
func ( stream, "[%s", arm_regnames [( given >> 16 ) & 0xf] );
if ( ( given & 0x01000000 ) != 0 )
{
int offset = given & 0xff;
if ( offset )
func ( stream, ", %s#%d]%s",
( ( given & 0x00800000 ) == 0 ? "-" : "" ),
offset * 4,
( ( given & 0x00200000 ) != 0 ? "!" : "" ) );
else
func ( stream, "]" );
}
else
{
int offset = given & 0xff;
if ( offset )
func ( stream, "], %s#%d",
( ( given & 0x00800000 ) == 0 ? "-" : "" ),
offset * 4 );
else
func ( stream, "]" );
}
break;
case 'B':
/* Print ARM V5 BLX( 1 ) address: pc+25 bits. */
{
bfd_vma address;
bfd_vma offset = 0;
if ( given & 0x00800000 )
/* Is signed, hi bits should be ones. */
offset = ( -1 ) ^ 0x00ffffff;
/* Offset is ( SignExtend( offset field )<<2 ). */
offset += given & 0x00ffffff;
offset <<= 2;
address = offset + pc + 8;
if ( given & 0x01000000 )
/* H bit allows addressing to 2-byte boundaries. */
address += 2;
info->print_address_func ( address, info );
}
break;
case 'I':
/* Print a Cirrus/DSP shift immediate. */
/* Immediates are 7bit signed ints with bits 0..3 in
bits 0..3 of opcode and bits 4..6 in bits 5..7
of opcode. */
{
int imm;
imm = ( given & 0xf ) | ( ( given & 0xe0 ) >> 1 );
/* Is ``imm'' a negative number? */
if ( imm & 0x40 )
imm |= ( -1 << 7 );
func ( stream, "%d", imm );
}
break;
case 'C':
func ( stream, "_" );
if ( given & 0x80000 )
func ( stream, "f" );
if ( given & 0x40000 )
func ( stream, "s" );
if ( given & 0x20000 )
func ( stream, "x" );
if ( given & 0x10000 )
func ( stream, "c" );
break;
case 'F':
switch ( given & 0x00408000 )
{
case 0:
func ( stream, "4" );
break;
case 0x8000:
func ( stream, "1" );
break;
case 0x00400000:
func ( stream, "2" );
break;
default:
func ( stream, "3" );
}
break;
case 'P':
switch ( given & 0x00080080 )
{
case 0:
func ( stream, "s" );
break;
case 0x80:
func ( stream, "d" );
break;
case 0x00080000:
func ( stream, "e" );
break;
default:
func ( stream, _( "<illegal precision>" ) );
break;
}
break;
case 'Q':
switch ( given & 0x00408000 )
{
case 0:
func ( stream, "s" );
break;
case 0x8000:
func ( stream, "d" );
break;
case 0x00400000:
func ( stream, "e" );
break;
default:
func ( stream, "p" );
break;
}
break;
case 'R':
switch ( given & 0x60 )
{
case 0:
break;
case 0x20:
func ( stream, "p" );
break;
case 0x40:
func ( stream, "m" );
break;
default:
func ( stream, "z" );
break;
}
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
int bitstart = *c++ - '0';
int bitend = 0;
while ( *c >= '0' && *c <= '9' )
bitstart = ( bitstart * 10 ) + *c++ - '0';
switch ( *c )
{
case '-':
c++;
while ( *c >= '0' && *c <= '9' )
bitend = ( bitend * 10 ) + *c++ - '0';
if ( !bitend )
abort ( );
switch ( *c )
{
case 'r':
{
long reg;
reg = given >> bitstart;
reg &= ( 2 << ( bitend - bitstart ) ) - 1;
func ( stream, "%s", arm_regnames[reg] );
}
break;
case 'd':
{
long reg;
reg = given >> bitstart;
reg &= ( 2 << ( bitend - bitstart ) ) - 1;
func ( stream, "%d", reg );
}
break;
case 'x':
{
long reg;
reg = given >> bitstart;
reg &= ( 2 << ( bitend - bitstart ) ) - 1;
func ( stream, "0x%08x", reg );
/* Some SWI instructions have special
meanings. */
if ( ( given & 0x0fffffff ) == 0x0FF00000 )
func ( stream, "\t; IMB" );
else if ( ( given & 0x0fffffff ) == 0x0FF00001 )
func ( stream, "\t; IMBRange" );
}
break;
case 'X':
{
long reg;
reg = given >> bitstart;
reg &= ( 2 << ( bitend - bitstart ) ) - 1;
func ( stream, "%01x", reg & 0xf );
}
break;
case 'f':
{
long reg;
reg = given >> bitstart;
reg &= ( 2 << ( bitend - bitstart ) ) - 1;
if ( reg > 7 )
func ( stream, "#%s",
arm_fp_const[reg & 7] );
else
func ( stream, "f%d", reg );
}
break;
default:
abort ( );
}
break;
case 'y':
case 'z':
{
int single = *c == 'y';
int regno;
switch ( bitstart )
{
case 4: /* Sm pair */
func ( stream, "{" );
/* Fall through. */
case 0: /* Sm, Dm */
regno = given & 0x0000000f;
if ( single )
{
regno <<= 1;
regno += ( given >> 5 ) & 1;
}
break;
case 1: /* Sd, Dd */
regno = ( given >> 12 ) & 0x0000000f;
if ( single )
{
regno <<= 1;
regno += ( given >> 22 ) & 1;
}
break;
case 2: /* Sn, Dn */
regno = ( given >> 16 ) & 0x0000000f;
if ( single )
{
regno <<= 1;
regno += ( given >> 7 ) & 1;
}
break;
case 3: /* List */
func ( stream, "{" );
regno = ( given >> 12 ) & 0x0000000f;
if ( single )
{
regno <<= 1;
regno += ( given >> 22 ) & 1;
}
break;
default:
abort ( );
}
func ( stream, "%c%d", single ? 's' : 'd', regno );
if ( bitstart == 3 )
{
int count = given & 0xff;
if ( single == 0 )
count >>= 1;
if ( --count )
{
func ( stream, "-%c%d",
single ? 's' : 'd',
regno + count );
}
func ( stream, "}" );
}
else if ( bitstart == 4 )
func ( stream, ", %c%d}", single ? 's' : 'd',
regno + 1 );
break;
}
case '`':
c++;
if ( ( given & ( 1 << bitstart ) ) == 0 )
func ( stream, "%c", *c );
break;
case '\'':
c++;
if ( ( given & ( 1 << bitstart ) ) != 0 )
func ( stream, "%c", *c );
break;
case '?':
++c;
if ( ( given & ( 1 << bitstart ) ) != 0 )
func ( stream, "%c", *c++ );
else
func ( stream, "%c", *++c );
break;
default:
abort ( );
}
break;
default:
abort ( );
}
}
}
else
func ( stream, "%c", *c );
}
return 4;
}
}
abort ( );
}
/* Print one instruction from PC on INFO->STREAM.
Return the size of the instruction. */
static int
print_insn_thumb ( pc, info, given )
bfd_vma pc;
struct disassemble_info * info;
long given;
{
struct thumb_opcode * insn;
void * stream = info->stream;
fprintf_ftype func = info->fprintf_func;
for ( insn = thumb_opcodes; insn->assembler; insn++ )
{
if ( ( given & insn->mask ) == insn->value )
{
char * c = insn->assembler;
/* Special processing for Thumb 2 instruction BL sequence: */
if ( !*c ) /* Check for empty ( not NULL ) assembler string. */
{
long offset;
info->bytes_per_chunk = 4;
info->bytes_per_line = 4;
offset = BDISP23 ( given );
offset = offset * 2 + pc + 4;
if ( ( given & 0x10000000 ) == 0 )
{
func ( stream, "blx\t" );
offset &= 0xfffffffc;
}
else
func ( stream, "bl\t" );
info->print_address_func ( offset, info );
return 4;
}
else
{
info->bytes_per_chunk = 2;
info->bytes_per_line = 4;
given &= 0xffff;
for ( ; *c; c++ )
{
if ( *c == '%' )
{
int domaskpc = 0;
int domasklr = 0;
switch ( *++c )
{
case '%':
func ( stream, "%%" );
break;
case 'S':
{
long reg;
reg = ( given >> 3 ) & 0x7;
if ( given & ( 1 << 6 ) )
reg += 8;
func ( stream, "%s", arm_regnames[reg] );
}
break;
case 'D':
{
long reg;
reg = given & 0x7;
if ( given & ( 1 << 7 ) )
reg += 8;
func ( stream, "%s", arm_regnames[reg] );
}
break;
case 'T':
func ( stream, "%s",
arm_conditional [( given >> 8 ) & 0xf] );
break;
case 'N':
if ( given & ( 1 << 8 ) )
domasklr = 1;
/* Fall through. */
case 'O':
if ( *c == 'O' && ( given & ( 1 << 8 ) ) )
domaskpc = 1;
/* Fall through. */
case 'M':
{
int started = 0;
int reg;
func ( stream, "{" );
/* It would be nice if we could spot
ranges, and generate the rS-rE format: */
for ( reg = 0; ( reg < 8 ); reg++ )
if ( ( given & ( 1 << reg ) ) != 0 )
{
if ( started )
func ( stream, ", " );
started = 1;
func ( stream, "%s", arm_regnames[reg] );
}
if ( domasklr )
{
if ( started )
func ( stream, ", " );
started = 1;
func ( stream, arm_regnames[14] /* "lr" */ );
}
if ( domaskpc )
{
if ( started )
func ( stream, ", " );
func ( stream, arm_regnames[15] /* "pc" */ );
}
func ( stream, "}" );
}
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
int bitstart = *c++ - '0';
int bitend = 0;
while ( *c >= '0' && *c <= '9' )
bitstart = ( bitstart * 10 ) + *c++ - '0';
switch ( *c )
{
case '-':
{
long reg;
c++;
while ( *c >= '0' && *c <= '9' )
bitend = ( bitend * 10 ) + *c++ - '0';
if ( !bitend )
abort ( );
reg = given >> bitstart;
reg &= ( 2 << ( bitend - bitstart ) ) - 1;
switch ( *c )
{
case 'r':
func ( stream, "%s", arm_regnames[reg] );
break;
case 'd':
func ( stream, "%d", reg );
break;
case 'H':
func ( stream, "%d", reg << 1 );
break;
case 'W':
func ( stream, "%d", reg << 2 );
break;
case 'a':
/* PC-relative address -- the bottom two
bits of the address are dropped
before the calculation. */
info->print_address_func
( ( ( pc + 4 ) & ~3 ) + ( reg << 2 ), info );
break;
case 'x':
func ( stream, "0x%04x", reg );
break;
case 'I':
reg = ( ( reg ^ ( 1 << bitend ) ) - ( 1 << bitend ) );
func ( stream, "%d", reg );
break;
case 'B':
reg = ( ( reg ^ ( 1 << bitend ) ) - ( 1 << bitend ) );
( *info->print_address_func )
( reg * 2 + pc + 4, info );
break;
default:
abort ( );
}
}
break;
case '\'':
c++;
if ( ( given & ( 1 << bitstart ) ) != 0 )
func ( stream, "%c", *c );
break;
case '?':
++c;
if ( ( given & ( 1 << bitstart ) ) != 0 )
func ( stream, "%c", *c++ );
else
func ( stream, "%c", *++c );
break;
default:
abort ( );
}
}
break;
default:
abort ( );
}
}
else
func ( stream, "%c", *c );
}
}
return 2;
}
}
/* No match. */
abort ( );
}
/* Parse an individual disassembler option. */
void
parse_arm_disassembler_option ( option )
char * option;
{
if ( option == NULL )
return;
if ( strneq ( option, "reg-names-", 10 ) )
{
int i;
option += 10;
for ( i = NUM_ARM_REGNAMES; i--; )
if ( streq ( option, regnames[i].name ) )
{
regname_selected = i;
break;
}
if ( i < 0 )
fprintf ( stderr, _( "Unrecognised register name set: %s\n" ), option );
}
else if ( streq ( option, "force-thumb" ) )
force_thumb = 1;
else if ( streq ( option, "no-force-thumb" ) )
force_thumb = 0;
else
fprintf ( stderr, _( "Unrecognised disassembler option: %s\n" ), option );
return;
}
/* Parse the string of disassembler options, spliting it at whitespaces. */
static void
parse_disassembler_options ( options )
char * options;
{
char * space;
if ( options == NULL )
return;
do
{
space = strchr ( options, ' ' );
if ( space )
{
* space = '\0';
parse_arm_disassembler_option ( options );
* space = ' ';
options = space + 1;
}
else
parse_arm_disassembler_option ( options );
}
while ( space );
}
/* NOTE: There are no checks in these routines that
the relevant number of data bytes exist. */
int
print_insn_arm ( pc, info )
bfd_vma pc;
struct disassemble_info * info;
{
unsigned char b[4];
long given;
int status;
int is_thumb;
int little;
if ( info->disassembler_options )
{
parse_disassembler_options ( info->disassembler_options );
/* To avoid repeated parsing of these options, we remove them here. */
info->disassembler_options = NULL;
}
is_thumb = force_thumb;
if ( pc & 1 )
{
is_thumb = 1;
pc &= ~( bfd_vma ) 1;
}
#if 0
if ( !is_thumb && info->symbols != NULL )
{
if ( bfd_asymbol_flavour ( *info->symbols ) == bfd_target_coff_flavour )
{
coff_symbol_type * cs;
cs = coffsymbol ( *info->symbols );
is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT
|| cs->native->u.syment.n_sclass == C_THUMBSTAT
|| cs->native->u.syment.n_sclass == C_THUMBLABEL
|| cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
|| cs->native->u.syment.n_sclass == C_THUMBSTATFUNC );
}
else if ( bfd_asymbol_flavour ( *info->symbols ) == bfd_target_elf_flavour )
{
elf_symbol_type * es;
unsigned int type;
es = *( elf_symbol_type ** )( info->symbols );
type = ELF_ST_TYPE ( es->internal_elf_sym.st_info );
is_thumb = ( type == STT_ARM_TFUNC ) || ( type == STT_ARM_16BIT );
}
}
#endif
little = ( info->endian == BFD_ENDIAN_LITTLE );
info->bytes_per_chunk = 4;
info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
if ( little )
{
status = info->read_memory_func ( pc, ( bfd_byte * ) &b[0], 4, info );
if ( status != 0 && is_thumb )
{
info->bytes_per_chunk = 2;
status = info->read_memory_func ( pc, ( bfd_byte * ) b, 2, info );
b[3] = b[2] = 0;
}
if ( status != 0 )
{
info->memory_error_func ( status, pc, info );
return -1;
}
given = ( b[0] ) | ( b[1] << 8 ) | ( b[2] << 16 ) | ( b[3] << 24 );
}
else
{
status = info->read_memory_func
( pc & ~ 0x3, ( bfd_byte * ) &b[0], 4, info );
if ( status != 0 )
{
info->memory_error_func ( status, pc, info );
return -1;
}
if ( is_thumb )
{
if ( pc & 0x2 )
{
given = ( b[2] << 8 ) | b[3];
status = info->read_memory_func
( ( pc + 4 ) & ~ 0x3, ( bfd_byte * ) b, 4, info );
if ( status != 0 )
{
info->memory_error_func ( status, pc + 4, info );
return -1;
}
given |= ( b[0] << 24 ) | ( b[1] << 16 );
}
else
given = ( b[0] << 8 ) | b[1] | ( b[2] << 24 ) | ( b[3] << 16 );
}
else
given = ( b[0] << 24 ) | ( b[1] << 16 ) | ( b[2] << 8 ) | ( b[3] );
}
if ( info->flags & INSN_HAS_RELOC )
/* If the instruction has a reloc associated with it, then
the offset field in the instruction will actually be the
addend for the reloc. ( We are using REL type relocs ).
In such cases, we can ignore the pc when computing
addresses, since the addend is not currently pc-relative. */
pc = 0;
if ( is_thumb )
status = print_insn_thumb ( pc, info, given );
else
status = print_insn_arm1 ( pc, info, given );
return status;
}
void
print_arm_disassembler_options ( FILE * stream )
{
int i;
fprintf ( stream, _( "\n\
The following ARM specific disassembler options are supported for use with\n\
the -M switch:\n" ) );
for ( i = NUM_ARM_REGNAMES; i--; )
fprintf ( stream, " reg-names-%s %*c%s\n",
regnames[i].name,
( int )( 14 - strlen ( regnames[i].name ) ), ' ',
regnames[i].description );
fprintf ( stream, " force-thumb Assume all insns are Thumb insns\n" );
fprintf ( stream, " no-force-thumb Examine preceeding label to determine an insn's type\n\n" );
}
1 /* Interface between the opcode library and its callers.
Written by Cygnus Support, 1993.
The opcode library ( libopcodes.a ) provides instruction decoders for
a large variety of instruction sets, callable with an identical
interface, for making instruction-processing programs more independent
of the instruction set being processed. */
#ifndef DIS_ASM_H
#define DIS_ASM_H
#include "/usr/include/stdlib.h"
#include "stdio.h"
#include "/usr/include/string.h"
#include "/usr/include/inttypes.h"
#define PARAMS( x ) x
typedef void *PTR;
typedef uint64_t bfd_vma;
typedef int64_t bfd_signed_vma;
typedef uint8_t bfd_byte;
#define sprintf_vma( s, x ) sprintf ( s, "%0" PRIx64, x )
#define BFD64
enum bfd_flavour {
bfd_target_unknown_flavour,
bfd_target_aout_flavour,
bfd_target_coff_flavour,
bfd_target_ecoff_flavour,
bfd_target_elf_flavour,
bfd_target_ieee_flavour,
bfd_target_nlm_flavour,
bfd_target_oasys_flavour,
bfd_target_tekhex_flavour,
bfd_target_srec_flavour,
bfd_target_ihex_flavour,
bfd_target_som_flavour,
bfd_target_os9k_flavour,
bfd_target_versados_flavour,
bfd_target_msdos_flavour,
bfd_target_evax_flavour
};
enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
enum bfd_architecture
{
bfd_arch_unknown, /* File arch not known */
bfd_arch_obscure, /* Arch known, not one of these */
bfd_arch_m68k, /* Motorola 68xxx */
#define bfd_mach_m68000 1
#define bfd_mach_m68008 2
#define bfd_mach_m68010 3
#define bfd_mach_m68020 4
#define bfd_mach_m68030 5
#define bfd_mach_m68040 6
#define bfd_mach_m68060 7
#define bfd_mach_cpu32 8
#define bfd_mach_mcf5200 9
#define bfd_mach_mcf5206e 10
#define bfd_mach_mcf5307 11
#define bfd_mach_mcf5407 12
#define bfd_mach_mcf528x 13
#define bfd_mach_mcfv4e 14
#define bfd_mach_mcf521x 15
#define bfd_mach_mcf5249 16
#define bfd_mach_mcf547x 17
#define bfd_mach_mcf548x 18
bfd_arch_vax, /* DEC Vax */
bfd_arch_i960, /* Intel 960 */
/* The order of the following is important.
lower number indicates a machine type that
only accepts a subset of the instructions
available to machines with higher numbers.
The exception is the "ca", which is
incompatible with all other machines except
"core". */
#define bfd_mach_i960_core 1
#define bfd_mach_i960_ka_sa 2
#define bfd_mach_i960_kb_sb 3
#define bfd_mach_i960_mc 4
#define bfd_mach_i960_xa 5
#define bfd_mach_i960_ca 6
#define bfd_mach_i960_jx 7
#define bfd_mach_i960_hx 8
bfd_arch_a29k, /* AMD 29000 */
bfd_arch_sparc, /* SPARC */
#define bfd_mach_sparc 1
/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */
#define bfd_mach_sparc_sparclet 2
#define bfd_mach_sparc_sparclite 3
#define bfd_mach_sparc_v8plus 4
#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */
#define bfd_mach_sparc_sparclite_le 6
#define bfd_mach_sparc_v9 7
#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */
#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */
#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */
/* Nonzero if MACH has the v9 instruction set. */
#define bfd_mach_sparc_v9_p( mach ) \
( ( mach ) >= bfd_mach_sparc_v8plus && ( mach ) <= bfd_mach_sparc_v9b \
&& ( mach ) != bfd_mach_sparc_sparclite_le )
bfd_arch_mips, /* MIPS Rxxxx */
#define bfd_mach_mips3000 3000
#define bfd_mach_mips3900 3900
#define bfd_mach_mips4000 4000
#define bfd_mach_mips4010 4010
#define bfd_mach_mips4100 4100
#define bfd_mach_mips4300 4300
#define bfd_mach_mips4400 4400
#define bfd_mach_mips4600 4600
#define bfd_mach_mips4650 4650
#define bfd_mach_mips5000 5000
#define bfd_mach_mips6000 6000
#define bfd_mach_mips8000 8000
#define bfd_mach_mips10000 10000
#define bfd_mach_mips16 16
bfd_arch_i386, /* Intel 386 */
#define bfd_mach_i386_i386 0
#define bfd_mach_i386_i8086 1
#define bfd_mach_i386_i386_intel_syntax 2
#define bfd_mach_x86_64 3
#define bfd_mach_x86_64_intel_syntax 4
bfd_arch_we32k, /* AT&T WE32xxx */
bfd_arch_tahoe, /* CCI/Harris Tahoe */
bfd_arch_i860, /* Intel 860 */
bfd_arch_romp, /* IBM ROMP PC/RT */
bfd_arch_alliant, /* Alliant */
bfd_arch_convex, /* Convex */
bfd_arch_m88k, /* Motorola 88xxx */
bfd_arch_pyramid, /* Pyramid Technology */
bfd_arch_h8300, /* Hitachi H8/300 */
#define bfd_mach_h8300 1
#define bfd_mach_h8300h 2
#define bfd_mach_h8300s 3
bfd_arch_powerpc, /* PowerPC */
#define bfd_mach_ppc 0
#define bfd_mach_ppc64 1
#define bfd_mach_ppc_403 403
#define bfd_mach_ppc_403gc 4030
#define bfd_mach_ppc_505 505
#define bfd_mach_ppc_601 601
#define bfd_mach_ppc_602 602
#define bfd_mach_ppc_603 603
#define bfd_mach_ppc_ec603e 6031
#define bfd_mach_ppc_604 604
#define bfd_mach_ppc_620 620
#define bfd_mach_ppc_630 630
#define bfd_mach_ppc_750 750
#define bfd_mach_ppc_860 860
#define bfd_mach_ppc_a35 35
#define bfd_mach_ppc_rs64ii 642
#define bfd_mach_ppc_rs64iii 643
#define bfd_mach_ppc_7400 7400
bfd_arch_rs6000, /* IBM RS/6000 */
bfd_arch_hppa, /* HP PA RISC */
bfd_arch_d10v, /* Mitsubishi D10V */
bfd_arch_z8k, /* Zilog Z8000 */
#define bfd_mach_z8001 1
#define bfd_mach_z8002 2
bfd_arch_h8500, /* Hitachi H8/500 */
bfd_arch_sh, /* Hitachi SH */
#define bfd_mach_sh 1
#define bfd_mach_sh2 0x20
#define bfd_mach_sh_dsp 0x2d
#define bfd_mach_sh2a 0x2a
#define bfd_mach_sh2a_nofpu 0x2b
#define bfd_mach_sh2e 0x2e
#define bfd_mach_sh3 0x30
#define bfd_mach_sh3_nommu 0x31
#define bfd_mach_sh3_dsp 0x3d
#define bfd_mach_sh3e 0x3e
#define bfd_mach_sh4 0x40
#define bfd_mach_sh4_nofpu 0x41
#define bfd_mach_sh4_nommu_nofpu 0x42
#define bfd_mach_sh4a 0x4a
#define bfd_mach_sh4a_nofpu 0x4b
#define bfd_mach_sh4al_dsp 0x4d
#define bfd_mach_sh5 0x50
bfd_arch_alpha, /* Dec Alpha */
bfd_arch_arm, /* Advanced Risc Machines ARM */
#define bfd_mach_arm_2 1
#define bfd_mach_arm_2a 2
#define bfd_mach_arm_3 3
#define bfd_mach_arm_3M 4
#define bfd_mach_arm_4 5
#define bfd_mach_arm_4T 6
bfd_arch_ns32k, /* National Semiconductors ns32000 */
bfd_arch_w65, /* WDC 65816 */
bfd_arch_tic30, /* Texas Instruments TMS320C30 */
bfd_arch_v850, /* NEC V850 */
#define bfd_mach_v850 0
bfd_arch_arc, /* Argonaut RISC Core */
#define bfd_mach_arc_base 0
bfd_arch_m32r, /* Mitsubishi M32R/D */
#define bfd_mach_m32r 0 /* backwards compatibility */
bfd_arch_mn10200, /* Matsushita MN10200 */
bfd_arch_mn10300, /* Matsushita MN10300 */
bfd_arch_last
};
typedef struct symbol_cache_entry
{
const char *name;
union
{
PTR p;
bfd_vma i;
} udata;
} asymbol;
typedef int ( *fprintf_ftype ) PARAMS( ( FILE*, const char*, ... ) );
enum dis_insn_type {
dis_noninsn, /* Not a valid instruction */
dis_nonbranch, /* Not a branch instruction */
dis_branch, /* Unconditional branch */
dis_condbranch, /* Conditional branch */
dis_jsr, /* Jump to subroutine */
dis_condjsr, /* Conditional jump to subroutine */
dis_dref, /* Data reference instruction */
dis_dref2 /* Two data references in instruction */
};
/* This struct is passed into the instruction decoding routine,
and is passed back out into each callback. The various fields are used
for conveying information from your main routine into your callbacks,
for passing information into the instruction decoders ( such as the
addresses of the callback functions ), or for passing information
back from the instruction decoders to their callers.
It must be initialized before it is first passed; this can be done
by hand, or using one of the initialization macros below. */
typedef struct disassemble_info {
fprintf_ftype fprintf_func;
FILE *stream;
PTR application_data;
/* Target description. We could replace this with a pointer to the bfd,
but that would require one. There currently isn't any such requirement
so to avoid introducing one we record these explicitly. */
/* The bfd_flavour. This can be bfd_target_unknown_flavour. */
enum bfd_flavour flavour;
/* The bfd_arch value. */
enum bfd_architecture arch;
/* The bfd_mach value. */
unsigned long mach;
/* Endianness ( for bi-endian cpus ). Mono-endian cpus can ignore this. */
enum bfd_endian endian;
/* An array of pointers to symbols either at the location being disassembled
or at the start of the function being disassembled. The array is sorted
so that the first symbol is intended to be the one used. The others are
present for any misc. purposes. This is not set reliably, but if it is
not NULL, it is correct. */
asymbol **symbols;
/* Number of symbols in array. */
int num_symbols;
/* For use by the disassembler.
The top 16 bits are reserved for public use ( and are documented here ).
The bottom 16 bits are for the internal use of the disassembler. */
unsigned long flags;
#define INSN_HAS_RELOC 0x80000000
PTR private_data;
/* Function used to get bytes to disassemble. MEMADDR is the
address of the stuff to be disassembled, MYADDR is the address to
put the bytes in, and LENGTH is the number of bytes to read.
INFO is a pointer to this struct.
Returns an errno value or 0 for success. */
int ( *read_memory_func )
PARAMS ( ( bfd_vma memaddr, bfd_byte *myaddr, int length,
struct disassemble_info *info ) );
/* Function which should be called if we get an error that we can't
recover from. STATUS is the errno value from read_memory_func and
MEMADDR is the address that we were trying to read. INFO is a
pointer to this struct. */
void ( *memory_error_func )
PARAMS ( ( int status, bfd_vma memaddr, struct disassemble_info *info ) );
/* Function called to print ADDR. */
void ( *print_address_func )
PARAMS ( ( bfd_vma addr, struct disassemble_info *info ) );
/* Function called to determine if there is a symbol at the given ADDR.
If there is, the function returns 1, otherwise it returns 0.
This is used by ports which support an overlay manager where
the overlay number is held in the top part of an address. In
some circumstances we want to include the overlay number in the
address, ( normally because there is a symbol associated with
that address ), but sometimes we want to mask out the overlay bits. */
int ( * symbol_at_address_func )
PARAMS ( ( bfd_vma addr, struct disassemble_info * info ) );
/* These are for buffer_read_memory. */
bfd_byte *buffer;
bfd_vma buffer_vma;
int buffer_length;
/* This variable may be set by the instruction decoder. It suggests
the number of bytes objdump should display on a single line. If
the instruction decoder sets this, it should always set it to
the same value in order to get reasonable looking output. */
int bytes_per_line;
/* the next two variables control the way objdump displays the raw data */
/* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */
/* output will look like this:
00: 00000000 00000000
with the chunks displayed according to "display_endian". */
int bytes_per_chunk;
enum bfd_endian display_endian;
/* Results from instruction decoders. Not all decoders yet support
this information. This info is set each time an instruction is
decoded, and is only valid for the last such instruction.
To determine whether this decoder supports this information, set
insn_info_valid to 0, decode an instruction, then check it. */
char insn_info_valid; /* Branch info has been set. */
char branch_delay_insns; /* How many sequential insn's will run before
a branch takes effect. ( 0 = normal ) */
char data_size; /* Size of data reference in insn, in bytes */
enum dis_insn_type insn_type; /* Type of instruction */
bfd_vma target; /* Target address of branch or dref, if known;
zero if unknown. */
bfd_vma target2; /* Second target address for dref2 */
/* Command line options specific to the target disassembler. */
char * disassembler_options;
} disassemble_info;
/* Standard disassemblers. Disassemble one instruction at the given
target address. Return number of bytes processed. */
typedef int ( *disassembler_ftype )
PARAMS( ( bfd_vma, disassemble_info * ) );
extern int print_insn_big_mips PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_little_mips PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_i386 PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_m68k PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_z8001 PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_z8002 PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_h8300 PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_h8300h PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_h8300s PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_h8500 PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_alpha PARAMS ( ( bfd_vma, disassemble_info* ) );
extern disassembler_ftype arc_get_disassembler PARAMS ( ( int, int ) );
extern int print_insn_arm PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_sparc PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_big_a29k PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_little_a29k PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_i960 PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_sh PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_shl PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_hppa PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_m32r PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_m88k PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_mn10200 PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_mn10300 PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_ns32k PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_big_powerpc PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_little_powerpc PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_rs6000 PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_w65 PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_d10v PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_v850 PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_tic30 PARAMS ( ( bfd_vma, disassemble_info* ) );
extern int print_insn_ppc PARAMS ( ( bfd_vma, disassemble_info* ) );
#if 0
/* Fetch the disassembler for a given BFD, if that support is available. */
extern disassembler_ftype disassembler PARAMS ( ( bfd * ) );
#endif
/* This block of definitions is for particular callers who read instructions
into a buffer before calling the instruction decoder. */
/* Here is a function which callers may wish to use for read_memory_func.
It gets bytes from a buffer. */
extern int buffer_read_memory
PARAMS ( ( bfd_vma, bfd_byte *, int, struct disassemble_info * ) );
/* This function goes with buffer_read_memory.
It prints a message using info->fprintf_func and info->stream. */
extern void perror_memory PARAMS ( ( int, bfd_vma, struct disassemble_info * ) );
/* Just print the address in hex. This is included for completeness even
though both GDB and objdump provide their own ( to print symbolic
addresses ). */
extern void generic_print_address
PARAMS ( ( bfd_vma, struct disassemble_info * ) );
/* Always true. */
extern int generic_symbol_at_address
PARAMS ( ( bfd_vma, struct disassemble_info * ) );
/* Macro to initialize a disassemble_info struct. This should be called
by all applications creating such a struct. */
#define INIT_DISASSEMBLE_INFO( INFO, STREAM, FPRINTF_FUNC ) \
( INFO ).flavour = bfd_target_unknown_flavour, \
( INFO ).arch = bfd_arch_unknown, \
( INFO ).mach = 0, \
( INFO ).endian = BFD_ENDIAN_UNKNOWN, \
INIT_DISASSEMBLE_INFO_NO_ARCH( INFO, STREAM, FPRINTF_FUNC )
/* Call this macro to initialize only the internal variables for the
disassembler. Architecture dependent things such as byte order, or machine
variant are not touched by this macro. This makes things much easier for
GDB which must initialize these things seperatly. */
424 #define INIT_DISASSEMBLE_INFO_NO_ARCH( INFO, STREAM, FPRINTF_FUNC ) \
425 ( INFO ).fprintf_func = ( FPRINTF_FUNC ), \
426 ( INFO ).stream = ( STREAM ), \
427 ( INFO ).symbols = NULL, \
( INFO ).num_symbols = 0, \
( INFO ).buffer = NULL, \
( INFO ).buffer_vma = 0, \
( INFO ).buffer_length = 0, \
( INFO ).read_memory_func = buffer_read_memory, \
( INFO ).memory_error_func = perror_memory, \
( INFO ).print_address_func = generic_print_address, \
( INFO ).symbol_at_address_func = generic_symbol_at_address, \
( INFO ).flags = 0, \
( INFO ).bytes_per_line = 0, \
( INFO ).bytes_per_chunk = 0, \
( INFO ).display_endian = BFD_ENDIAN_UNKNOWN, \
( INFO ).disassembler_options = NULL, \
( INFO ).insn_info_valid = 0
#define _( x ) x
#define ATTRIBUTE_UNUSED __attribute__( ( unused ) )
/* from libbfd */
bfd_vma bfd_getl32 ( const bfd_byte *addr );
bfd_vma bfd_getb32 ( const bfd_byte *addr );
bfd_vma bfd_getl16 ( const bfd_byte *addr );
bfd_vma bfd_getb16 ( const bfd_byte *addr );
typedef enum bfd_boolean {false, true} boolean;
typedef boolean bfd_boolean;
#endif /* ! defined ( DIS_ASM_H ) */
/* Copyright ( C ) 1997-2001, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or ( at your option ) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/*
* ISO C99: 7.8 Format conversion of integer types <inttypes.h>
*/
#ifndef _INTTYPES_H
#define _INTTYPES_H 1
#include <features.h>
/* Get the type definitions. */
#include <stdint.h>
/* Get a definition for wchar_t. But we must not define wchar_t itself. */
#ifndef ____gwchar_t_defined
# ifdef __cplusplus
# define __gwchar_t wchar_t
# elif defined __WCHAR_TYPE__
typedef __WCHAR_TYPE__ __gwchar_t;
# else
# define __need_wchar_t
# include <stddef.h>
typedef wchar_t __gwchar_t;
# endif
# define ____gwchar_t_defined 1
#endif
/* The ISO C99 standard specifies that these macros must only be
defined if explicitly requested. */
#if !defined __cplusplus || defined __STDC_FORMAT_MACROS
# if __WORDSIZE == 64
# define __PRI64_PREFIX "l"
# define __PRIPTR_PREFIX "l"
# else
# define __PRI64_PREFIX "ll"
# define __PRIPTR_PREFIX
# endif
/* Macros for printing format specifiers. */
/* Decimal notation. */
# define PRId8 "d"
# define PRId16 "d"
# define PRId32 "d"
# define PRId64 __PRI64_PREFIX "d"
# define PRIdLEAST8 "d"
# define PRIdLEAST16 "d"
# define PRIdLEAST32 "d"
# define PRIdLEAST64 __PRI64_PREFIX "d"
# define PRIdFAST8 "d"
# define PRIdFAST16 __PRIPTR_PREFIX "d"
# define PRIdFAST32 __PRIPTR_PREFIX "d"
# define PRIdFAST64 __PRI64_PREFIX "d"
# define PRIi8 "i"
# define PRIi16 "i"
# define PRIi32 "i"
# define PRIi64 __PRI64_PREFIX "i"
# define PRIiLEAST8 "i"
# define PRIiLEAST16 "i"
# define PRIiLEAST32 "i"
# define PRIiLEAST64 __PRI64_PREFIX "i"
# define PRIiFAST8 "i"
# define PRIiFAST16 __PRIPTR_PREFIX "i"
# define PRIiFAST32 __PRIPTR_PREFIX "i"
# define PRIiFAST64 __PRI64_PREFIX "i"
/* Octal notation. */
# define PRIo8 "o"
# define PRIo16 "o"
# define PRIo32 "o"
# define PRIo64 __PRI64_PREFIX "o"
# define PRIoLEAST8 "o"
# define PRIoLEAST16 "o"
# define PRIoLEAST32 "o"
# define PRIoLEAST64 __PRI64_PREFIX "o"
# define PRIoFAST8 "o"
# define PRIoFAST16 __PRIPTR_PREFIX "o"
# define PRIoFAST32 __PRIPTR_PREFIX "o"
# define PRIoFAST64 __PRI64_PREFIX "o"
/* Unsigned integers. */
# define PRIu8 "u"
# define PRIu16 "u"
# define PRIu32 "u"
# define PRIu64 __PRI64_PREFIX "u"
# define PRIuLEAST8 "u"
# define PRIuLEAST16 "u"
# define PRIuLEAST32 "u"
# define PRIuLEAST64 __PRI64_PREFIX "u"
# define PRIuFAST8 "u"
# define PRIuFAST16 __PRIPTR_PREFIX "u"
# define PRIuFAST32 __PRIPTR_PREFIX "u"
# define PRIuFAST64 __PRI64_PREFIX "u"
/* lowercase hexadecimal notation. */
# define PRIx8 "x"
# define PRIx16 "x"
# define PRIx32 "x"
# define PRIx64 __PRI64_PREFIX "x"
# define PRIxLEAST8 "x"
# define PRIxLEAST16 "x"
# define PRIxLEAST32 "x"
# define PRIxLEAST64 __PRI64_PREFIX "x"
# define PRIxFAST8 "x"
# define PRIxFAST16 __PRIPTR_PREFIX "x"
# define PRIxFAST32 __PRIPTR_PREFIX "x"
# define PRIxFAST64 __PRI64_PREFIX "x"
/* UPPERCASE hexadecimal notation. */
# define PRIX8 "X"
# define PRIX16 "X"
# define PRIX32 "X"
# define PRIX64 __PRI64_PREFIX "X"
# define PRIXLEAST8 "X"
# define PRIXLEAST16 "X"
# define PRIXLEAST32 "X"
# define PRIXLEAST64 __PRI64_PREFIX "X"
# define PRIXFAST8 "X"
# define PRIXFAST16 __PRIPTR_PREFIX "X"
# define PRIXFAST32 __PRIPTR_PREFIX "X"
# define PRIXFAST64 __PRI64_PREFIX "X"
/* Macros for printing `intmax_t' and `uintmax_t'. */
# define PRIdMAX __PRI64_PREFIX "d"
# define PRIiMAX __PRI64_PREFIX "i"
# define PRIoMAX __PRI64_PREFIX "o"
# define PRIuMAX __PRI64_PREFIX "u"
# define PRIxMAX __PRI64_PREFIX "x"
# define PRIXMAX __PRI64_PREFIX "X"
/* Macros for printing `intptr_t' and `uintptr_t'. */
# define PRIdPTR __PRIPTR_PREFIX "d"
# define PRIiPTR __PRIPTR_PREFIX "i"
# define PRIoPTR __PRIPTR_PREFIX "o"
# define PRIuPTR __PRIPTR_PREFIX "u"
# define PRIxPTR __PRIPTR_PREFIX "x"
# define PRIXPTR __PRIPTR_PREFIX "X"
/* Macros for scanning format specifiers. */
/* Signed decimal notation. */
# define SCNd8 "hhd"
# define SCNd16 "hd"
# define SCNd32 "d"
# define SCNd64 __PRI64_PREFIX "d"
# define SCNdLEAST8 "hhd"
# define SCNdLEAST16 "hd"
# define SCNdLEAST32 "d"
# define SCNdLEAST64 __PRI64_PREFIX "d"
# define SCNdFAST8 "hhd"
# define SCNdFAST16 __PRIPTR_PREFIX "d"
# define SCNdFAST32 __PRIPTR_PREFIX "d"
# define SCNdFAST64 __PRI64_PREFIX "d"
/* Signed decimal notation. */
# define SCNi8 "hhi"
# define SCNi16 "hi"
# define SCNi32 "i"
# define SCNi64 __PRI64_PREFIX "i"
# define SCNiLEAST8 "hhi"
# define SCNiLEAST16 "hi"
# define SCNiLEAST32 "i"
# define SCNiLEAST64 __PRI64_PREFIX "i"
# define SCNiFAST8 "hhi"
# define SCNiFAST16 __PRIPTR_PREFIX "i"
# define SCNiFAST32 __PRIPTR_PREFIX "i"
# define SCNiFAST64 __PRI64_PREFIX "i"
/* Unsigned decimal notation. */
# define SCNu8 "hhu"
# define SCNu16 "hu"
# define SCNu32 "u"
# define SCNu64 __PRI64_PREFIX "u"
# define SCNuLEAST8 "hhu"
# define SCNuLEAST16 "hu"
# define SCNuLEAST32 "u"
# define SCNuLEAST64 __PRI64_PREFIX "u"
# define SCNuFAST8 "hhu"
# define SCNuFAST16 __PRIPTR_PREFIX "u"
# define SCNuFAST32 __PRIPTR_PREFIX "u"
# define SCNuFAST64 __PRI64_PREFIX "u"
/* Octal notation. */
# define SCNo8 "hho"
# define SCNo16 "ho"
# define SCNo32 "o"
# define SCNo64 __PRI64_PREFIX "o"
# define SCNoLEAST8 "hho"
# define SCNoLEAST16 "ho"
# define SCNoLEAST32 "o"
# define SCNoLEAST64 __PRI64_PREFIX "o"
# define SCNoFAST8 "hho"
# define SCNoFAST16 __PRIPTR_PREFIX "o"
# define SCNoFAST32 __PRIPTR_PREFIX "o"
# define SCNoFAST64 __PRI64_PREFIX "o"
/* Hexadecimal notation. */
# define SCNx8 "hhx"
# define SCNx16 "hx"
# define SCNx32 "x"
# define SCNx64 __PRI64_PREFIX "x"
# define SCNxLEAST8 "hhx"
# define SCNxLEAST16 "hx"
# define SCNxLEAST32 "x"
# define SCNxLEAST64 __PRI64_PREFIX "x"
# define SCNxFAST8 "hhx"
# define SCNxFAST16 __PRIPTR_PREFIX "x"
# define SCNxFAST32 __PRIPTR_PREFIX "x"
# define SCNxFAST64 __PRI64_PREFIX "x"
/* Macros for scanning `intmax_t' and `uintmax_t'. */
# define SCNdMAX __PRI64_PREFIX "d"
# define SCNiMAX __PRI64_PREFIX "i"
# define SCNoMAX __PRI64_PREFIX "o"
# define SCNuMAX __PRI64_PREFIX "u"
# define SCNxMAX __PRI64_PREFIX "x"
/* Macros for scaning `intptr_t' and `uintptr_t'. */
# define SCNdPTR __PRIPTR_PREFIX "d"
# define SCNiPTR __PRIPTR_PREFIX "i"
# define SCNoPTR __PRIPTR_PREFIX "o"
# define SCNuPTR __PRIPTR_PREFIX "u"
# define SCNxPTR __PRIPTR_PREFIX "x"
#endif /* C++ && format macros */
274 __BEGIN_DECLS
#if __WORDSIZE == 64
/* We have to define the `uintmax_t' type using `ldiv_t'. */
typedef struct
{
long int quot; /* Quotient. */
long int rem; /* Remainder. */
} imaxdiv_t;
#else
/* We have to define the `uintmax_t' type using `lldiv_t'. */
typedef struct
{
long long int quot; /* Quotient. */
long long int rem; /* Remainder. */
} imaxdiv_t;
#endif
/* Compute absolute value of N. */
298 extern intmax_t imaxabs ( intmax_t __n ) __THROW __attribute__ ( ( __const__ ) );
/* Return the `imaxdiv_t' representation of the value of NUMER over DENOM. */
301 extern imaxdiv_t imaxdiv ( intmax_t __numer, intmax_t __denom )
302 __THROW __attribute__ ( ( __const__ ) );
/* Like `strtol' but convert to `intmax_t'. */
305 extern intmax_t strtoimax ( __const char *__restrict __nptr,
char **__restrict __endptr, int __base ) __THROW;
/* Like `strtoul' but convert to `uintmax_t'. */
309 extern uintmax_t strtoumax ( __const char *__restrict __nptr,
char ** __restrict __endptr, int __base ) __THROW;
/* Like `wcstol' but convert to `intmax_t'. */
313 extern intmax_t wcstoimax ( __const __gwchar_t *__restrict __nptr,
__gwchar_t **__restrict __endptr, int __base )
__THROW;
/* Like `wcstoul' but convert to `uintmax_t'. */
318 extern uintmax_t wcstoumax ( __const __gwchar_t *__restrict __nptr,
__gwchar_t ** __restrict __endptr, int __base )
__THROW;
#ifdef __USE_EXTERN_INLINES
# if __WORDSIZE == 64
/* Like `strtol' but convert to `intmax_t'. */
# ifndef __strtol_internal_defined
328 extern long int __strtol_internal ( __const char *__restrict __nptr,
char **__restrict __endptr,
int __base, int __group ) __THROW;
# define __strtol_internal_defined 1
# endif
extern __inline intmax_t
__NTH ( strtoimax ( __const char *__restrict nptr, char **__restrict endptr,
int base ) )
{
337 return __strtol_internal ( nptr, endptr, base, 0 );
}
/* Like `strtoul' but convert to `uintmax_t'. */
# ifndef __strtoul_internal_defined
extern unsigned long int __strtoul_internal ( __const char *
__restrict __nptr,
char ** __restrict __endptr,
int __base, int __group ) __THROW;
# define __strtoul_internal_defined 1
# endif
extern __inline uintmax_t
__NTH ( strtoumax ( __const char *__restrict nptr, char **__restrict endptr,
int base ) )
{
return __strtoul_internal ( nptr, endptr, base, 0 );
}
/* Like `wcstol' but convert to `intmax_t'. */
# ifndef __wcstol_internal_defined
extern long int __wcstol_internal ( __const __gwchar_t * __restrict __nptr,
__gwchar_t **__restrict __endptr,
int __base, int __group ) __THROW;
# define __wcstol_internal_defined 1
# endif
extern __inline intmax_t
__NTH ( wcstoimax ( __const __gwchar_t *__restrict nptr,
__gwchar_t **__restrict endptr, int base ) )
{
return __wcstol_internal ( nptr, endptr, base, 0 );
}
/* Like `wcstoul' but convert to `uintmax_t'. */
# ifndef __wcstoul_internal_defined
extern unsigned long int __wcstoul_internal ( __const __gwchar_t *
__restrict __nptr,
__gwchar_t **
__restrict __endptr,
int __base, int __group ) __THROW;
# define __wcstoul_internal_defined 1
# endif
extern __inline uintmax_t
__NTH ( wcstoumax ( __const __gwchar_t *__restrict nptr,
__gwchar_t **__restrict endptr, int base ) )
{
return __wcstoul_internal ( nptr, endptr, base, 0 );
}
# else /* __WORDSIZE == 32 */
/* Like `strtol' but convert to `intmax_t'. */
# ifndef __strtoll_internal_defined
__extension__
extern long long int __strtoll_internal ( __const char *__restrict __nptr,
char **__restrict __endptr,
int __base, int __group ) __THROW;
# define __strtoll_internal_defined 1
# endif
extern __inline intmax_t
__NTH ( strtoimax ( __const char *__restrict nptr, char **__restrict endptr,
int base ) )
{
return __strtoll_internal ( nptr, endptr, base, 0 );
}
/* Like `strtoul' but convert to `uintmax_t'. */
# ifndef __strtoull_internal_defined
__extension__
extern unsigned long long int __strtoull_internal ( __const char *
__restrict __nptr,
char **
__restrict __endptr,
int __base,
int __group ) __THROW;
# define __strtoull_internal_defined 1
# endif
extern __inline uintmax_t
__NTH ( strtoumax ( __const char *__restrict nptr, char **__restrict endptr,
int base ) )
{
return __strtoull_internal ( nptr, endptr, base, 0 );
}
/* Like `wcstol' but convert to `intmax_t'. */
# ifndef __wcstoll_internal_defined
__extension__
extern long long int __wcstoll_internal ( __const __gwchar_t *
__restrict __nptr,
__gwchar_t **__restrict __endptr,
int __base, int __group ) __THROW;
# define __wcstoll_internal_defined 1
# endif
extern __inline intmax_t
__NTH ( wcstoimax ( __const __gwchar_t *__restrict nptr,
__gwchar_t **__restrict endptr, int base ) )
{
return __wcstoll_internal ( nptr, endptr, base, 0 );
}
/* Like `wcstoul' but convert to `uintmax_t'. */
# ifndef __wcstoull_internal_defined
__extension__
extern unsigned long long int __wcstoull_internal ( __const __gwchar_t *
__restrict __nptr,
__gwchar_t **
__restrict __endptr,
int __base,
int __group ) __THROW;
# define __wcstoull_internal_defined 1
# endif
extern __inline uintmax_t
__NTH ( wcstoumax ( __const __gwchar_t *__restrict nptr,
__gwchar_t **__restrict endptr, int base ) )
{
return __wcstoull_internal ( nptr, endptr, base, 0 );
}
# endif /* __WORDSIZE == 32 */
#endif /* Use extern inlines. */
__END_DECLS
#endif /* inttypes.h */
1 #include <linux/string.h>
#include "mm.h"
#include "stdio.h"
#define FALSE 0
#define TRUE 1
8 void create_pg_table( phys_mem_t *mem_map,
unsigned int map_size,
unsigned long *pgtbl_base_ptr )
{
unsigned long i, table_entry, desc_entry;
unsigned long fields;
unsigned long physical;
int j;
printf( "no_entries = %d, pg_tbl_base = %p\n", map_size, pgtbl_base_ptr );
table_entry = 0;
for( desc_entry = 0; desc_entry < map_size; desc_entry++, mem_map++ )
{
/* Now create the page tables */
fields = ( mem_map->access << 10 ) | ( mem_map->access << 8 ) | ( mem_map->access << 6 ) |
( mem_map->access << 4 ) | ( mem_map->flags << 2 );
if( mem_map->entrytype == 'L' )
{
fields |= 1;
}
else
{
fields |= 2;
}
/* create entries for the descriptor */
i = mem_map->virt_addr_start;
physical = mem_map->phys_addr;
while( i < mem_map->virt_addr_end )
{
if( mem_map->entrytype == 'L' )
{
for( j=16; j; j-- )
{
pgtbl_base_ptr[table_entry++] = physical | fields;
}
physical += 0x10000;
i += 0x10000;
// printf( "phys = %lx, virt = %lx, table_entry = %lx, pg_tbl_entry = %lx\n",
// physical, i, table_entry, pgtbl_base_ptr[table_entry - 1] );
}
else
{
pgtbl_base_ptr[table_entry++] = physical | fields;
physical += 0x1000;
i += 0x1000;
}
}
}
while ( table_entry < 1024 )
{
pgtbl_base_ptr[table_entry++] = 0;
}
return;
}
71 void create_pg_dir( phys_mem_t *mem_map,
unsigned int map_size,
unsigned long *pg_dir_base )
{
unsigned long i, table_entry, desc_entry, j;
unsigned long fields;
unsigned long physical;
unsigned long pagescount = 0;
printf( "no_entries = %d, pg_dir_base = %p\n", map_size, pg_dir_base );
table_entry = 0;
for( desc_entry = 0; desc_entry < map_size; desc_entry++, mem_map++ )
{
/* Length is a multiple of 1MB use segment descriptors */
if( table_entry != ( mem_map->virt_addr_start >> 20 ) )
{
printf( "MMU Table synchronisation error!\n table_entry = %08lx, v_base = %08lx, pagescount = %ld\n",
table_entry, mem_map->virt_addr_start, pagescount );
}
if( mem_map->entrytype == 'S' || mem_map->entrytype == 'F' )
{
if( mem_map->entrytype == 'S' )
{
fields = 0x12 | ( mem_map->access << 10 ) | ( mem_map->flags << 2 );
}
else
{
fields = 0; // generate fault on access
}
physical = ( unsigned long ) mem_map->phys_addr;
for( i = mem_map->virt_addr_start; i < mem_map->virt_addr_end; )
{
pg_dir_base[table_entry] = physical | fields;
//printf( "phys = %x, virt = %x, table_entry = %x, pgd_entry = %x\n",
// physical, i, table_entry, pg_dir_base[table_entry] );
table_entry++;
physical += 0x100000;
i += 0x100000;
if( i == 0x00000000 ) break;
}
}
else
{
physical = ( unsigned long ) mem_map->phys_addr;
for( i = mem_map->virt_addr_start; i < mem_map->virt_addr_end;
physical += 0x400000, i += 0x400000 )
{
fields = 0x11 + ( unsigned long )pg_dir_base +
0x4000 + 0x400 * pagescount++;
/* Repeat 4 times since the page table covers 4MB for virtual address */
for( j = 4; j > 0; j-- )
{
pg_dir_base[table_entry++] = fields;
}
}
}
}
while ( table_entry < 4096 )
{
pg_dir_base[++table_entry] = 0;
}
return;
}
143 unsigned long create_mem_map ( unsigned long *pg_dir_base,
phys_mem_t *mem_map_base )
{
phys_mem_t temp_mem_desc;
unsigned long i;
unsigned int create_new_descriptor = FALSE;
unsigned long num_entries = 0;
printf( "create_mem_map: %p %p\n", pg_dir_base, mem_map_base );
for( i = 0; i < 4096; i++ )
{
temp_mem_desc.virt_addr_start = i << 20;
switch ( pg_dir_base[i] & 3 )
{
case 0x0:
temp_mem_desc.entrytype = FAULT;
temp_mem_desc.virt_addr_end = ( i << 20 ) + 0xFFFFF;
if( ( num_entries ) &&
( temp_mem_desc.virt_addr_start == ( mem_map_base->virt_addr_end + 1 ) ) &&
( temp_mem_desc.entrytype == mem_map_base->entrytype ) )
{
/* Add to previous descriptor */
create_new_descriptor = FALSE;
}
else
{
/* Create new descriptor */
create_new_descriptor = TRUE;
}
break;
case 0x1:
temp_mem_desc.entrytype = TINYPAGES;
temp_mem_desc.phys_addr = pg_dir_base[i] &= ~0xFFF;
create_new_descriptor = TRUE;
break;
case 0x2:
temp_mem_desc.entrytype = SECTION;
temp_mem_desc.flags = ( pg_dir_base[i] >> 2 ) & 3;
temp_mem_desc.access = ( pg_dir_base[i] >> 10 ) & 3;
temp_mem_desc.phys_addr = pg_dir_base[i] &= ~0xFFF;
temp_mem_desc.virt_addr_end = ( i << 20 ) + 0xFFFFF;
if( ( num_entries ) &&
( temp_mem_desc.virt_addr_start == ( mem_map_base->virt_addr_end + 1 ) ) &&
( temp_mem_desc.entrytype == mem_map_base->entrytype ) &&
// ( temp_mem_desc.phys_addr == ( mem_map_base->phys_addr + 0x100000 ) ) &&
( temp_mem_desc.flags == mem_map_base->flags ) &&
( temp_mem_desc.access == mem_map_base->access ) )
{
/* Add to previous descriptor */
create_new_descriptor = FALSE;
// printf( "create new desc\n" );
}
else
{
/* Create new descriptor */
create_new_descriptor = TRUE;
}
break;
case 0x3:
temp_mem_desc.entrytype = PAGES;
temp_mem_desc.phys_addr = pg_dir_base[i] &= ~0x3FF;
create_new_descriptor = TRUE;
break;
}
/* printf( "temp_mem_desc : %8lx %8lx %8lx %lx %lx %d\n",
temp_mem_desc.virt_addr_start,
temp_mem_desc.virt_addr_end,
temp_mem_desc.phys_addr,
temp_mem_desc.entrytype,
temp_mem_desc.flags, create_new_descriptor );
*/
if( create_new_descriptor == FALSE )
{
mem_map_base->virt_addr_end = temp_mem_desc.virt_addr_end;
}
else
{
if( num_entries )
mem_map_base++;
num_entries++;
memcpy( mem_map_base, &temp_mem_desc, sizeof( phys_mem_t ) );
printf( "mem_map_desc : %8lx %8lx %8lx %lx %lx %d\n",
mem_map_base->virt_addr_start,
mem_map_base->virt_addr_end,
mem_map_base->phys_addr,
mem_map_base->entrytype,
mem_map_base->flags, create_new_descriptor );
}
}
return( num_entries );
}
1
#define SECTION 'S'
#define PAGES 'P'
#define FAULT 'F'
#define TINYPAGES 'T'
#define LARGEPAGES 'L'
#define SMALLPAGES 'D'
#define NO_ACCESS 0
#define SVC_READWRITE 1
#define NO_USR_WRITE 2
#define FULL_ACCESS 3
#define VM_FLAG_CACHEABLE 2
#define VM_FLAG_BUFFERABLE 1
typedef struct phys_mem
{
unsigned long virt_addr_start;
unsigned long virt_addr_end;
unsigned long phys_addr;
unsigned long entrytype; /* PAGES, SECTION */
unsigned long access; /* NO_ACCESS, SVC_READWRITE,
NO_USR_WRITE, FULL_ACCESS, FAULT */
unsigned long flags;
} phys_mem_t;
29 extern void create_pg_dir( phys_mem_t *, unsigned int, unsigned long * );
30 extern void create_pg_table( phys_mem_t *, unsigned int, unsigned long * );
31 unsigned long create_mem_map( unsigned long *, phys_mem_t * );
1 /*
* Copyright ( C ) Paul Mackerras 1997.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or ( at your option ) any later version.
*/
#include <stdarg.h>
#include <stddef.h>
#include <linux/string.h>
#include "stdio.h"
#ifdef STANDALONE_DEBUG
#define putstr printf
#else
//static void putstr( const char *ptr );
#include <linux/compiler.h>
#include <asm/arch/uncompress.h>
#ifdef CONFIG_DEBUG_ICEDCC
#ifdef CONFIG_CPU_V6
27 static void icedcc_putc( int ch )
{
int status, i = 0x4000000;
do {
if ( --i < 0 )
return;
asm volatile ( "mrc p14, 0, %0, c0, c1, 0" : "=r" ( status ) );
} while ( status & ( 1 << 29 ) );
asm( "mcr p14, 0, %0, c0, c5, 0" : : "r" ( ch ) );
}
#else
43 static void icedcc_putc( int ch )
{
int status, i = 0x4000000;
do {
if ( --i < 0 )
return;
asm volatile ( "mrc p14, 0, %0, c0, c0, 0" : "=r" ( status ) );
} while ( status & 2 );
asm( "mcr p14, 0, %0, c1, c0, 0" : : "r" ( ch ) );
}
#endif
#define putc( ch ) icedcc_putc( ch )
#define flush( ) do { } while ( 0 )
#endif
63 void putstr( const char *ptr )
{
char c;
while ( ( c = *ptr++ ) != '\0' ) {
if ( c == '\n' )
putc( '\r' );
putc( c );
}
flush( );
}
#endif
/**
* * strlen - Find the length of a string
* * @s: The string to be sized
* */
81 size_t strlen( const char *s )
{
const char *sc;
for ( sc = s; *sc != '\0'; ++sc )
/* nothing */;
return sc - s;
}
90 size_t strnlen( const char * s, size_t count )
{
const char *sc;
for ( sc = s; count-- && *sc != '\0'; ++sc )
/* nothing */;
return sc - s;
}
/**
* * memcpy - Copy one area of memory to another
* * @dest: Where to copy to
* * @src: Where to copy from
* * @count: The size of the area.
* *
* * You should not use this function to access IO space, use memcpy_toio( )
* * or memcpy_fromio( ) instead.
* */
108 void *memcpy( void *dest, const void *src, size_t count )
{
char *tmp = dest;
const char *s = src;
while ( count-- )
*tmp++ = *s++;
return dest;
}
/*extern unsigned int __div64_32( unsigned long long *dividend,
unsigned int divisor );
The unnecessary pointer compare is there
* to check for type safety ( n must be 64bit )
# define do_div( n, base ) ( { \
unsigned int __base = ( base ); \
unsigned int __rem; \
( void )( ( ( typeof( ( n ) ) * )0 ) == ( ( unsigned long long * )0 ) ); \
if ( ( ( n ) >> 32 ) == 0 ) { \
__rem = ( unsigned int )( n ) % __base; \
( n ) = ( unsigned int )( n ) / __base; \
} else \
__rem = __div64_32( &( n ), __base ); \
__rem; \
} )
*/
139 static int skip_atoi( const char **s )
{
int i, c;
for ( i = 0; '0' <= ( c = **s ) && c <= '9'; ++*s )
i = i*10 + c - '0';
return i;
}
#define ZEROPAD 1 /* pad with zero */
#define SIGN 2 /* unsigned/signed long */
#define PLUS 4 /* show plus */
#define SPACE 8 /* space if plus */
#define LEFT 16 /* left justified */
#define SPECIAL 32 /* 0x */
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
156 static char * number( char * str, unsigned long long num, int base, int size, int precision, int type )
{
char c, sign, tmp[66];
unsigned long rem, cnt;
const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
int i;
if ( type & LARGE )
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if ( type & LEFT )
type &= ~ZEROPAD;
if ( base < 2 || base > 36 )
return 0;
c = ( type & ZEROPAD ) ? '0' : ' ';
sign = 0;
if ( type & SIGN ) {
if ( ( signed long long )num < 0 ) {
sign = '-';
num = - ( signed long long )num;
size--;
} else if ( type & PLUS ) {
sign = '+';
size--;
} else if ( type & SPACE ) {
sign = ' ';
size--;
}
}
if ( type & SPECIAL ) {
if ( base == 16 )
size -= 2;
else if ( base == 8 )
size--;
}
i = 0;
if ( num == 0 )
tmp[i++]='0';
else while ( num != 0 ) {
for( cnt=0;num >= base;cnt++ ) {
num = ( ( unsigned long ) num ) - ( unsigned ) base;
}
rem = num;
num = cnt;
tmp[i++] = digits[rem];
}
if ( i > precision )
precision = i;
size -= precision;
if ( !( type&( ZEROPAD+LEFT ) ) )
while( size-->0 )
*str++ = ' ';
if ( sign )
*str++ = sign;
if ( type & SPECIAL ) {
if ( base==8 )
*str++ = '0';
else if ( base==16 ) {
*str++ = '0';
*str++ = digits[33];
}
}
if ( !( type & LEFT ) )
while ( size-- > 0 )
*str++ = c;
while ( i < precision-- )
*str++ = '0';
while ( i-- > 0 )
*str++ = tmp[i];
while ( size-- > 0 )
*str++ = ' ';
return str;
}
229 int vsprintf( char *buf, const char *fmt, va_list args )
{
int len;
unsigned long long num;
int i, base;
char * str;
const char *s;
int flags; /* flags to number( ) */
int field_width; /* width of output field */
int precision; /* min. # of digits for integers; max
number of chars for from string */
int qualifier; /* 'h', 'l', or 'L' for integer fields */
/* 'z' support added 23/7/1999 S.H. */
/* 'z' changed to 'Z' --davidm 1/25/99 */
for ( str=buf ; *fmt ; ++fmt ) {
if ( *fmt != '%' ) {
*str++ = *fmt;
continue;
}
/* process flags */
flags = 0;
repeat:
++fmt; /* this also skips first '%' */
switch ( *fmt ) {
case '-': flags |= LEFT; goto repeat;
case '+': flags |= PLUS; goto repeat;
case ' ': flags |= SPACE; goto repeat;
case '#': flags |= SPECIAL; goto repeat;
case '0': flags |= ZEROPAD; goto repeat;
}
/* get field width */
field_width = -1;
if ( '0' <= *fmt && *fmt <= '9' )
field_width = skip_atoi( &fmt );
else if ( *fmt == '*' ) {
++fmt;
/* it's the next argument */
field_width = va_arg( args, int );
if ( field_width < 0 ) {
field_width = -field_width;
flags |= LEFT;
}
}
/* get the precision */
precision = -1;
if ( *fmt == '.' ) {
++fmt;
if ( '0' <= *fmt && *fmt <= '9' )
precision = skip_atoi( &fmt );
else if ( *fmt == '*' ) {
++fmt;
/* it's the next argument */
precision = va_arg( args, int );
}
if ( precision < 0 )
precision = 0;
}
/* get the conversion qualifier */
qualifier = -1;
if ( *fmt == 'l' && *( fmt + 1 ) == 'l' ) {
qualifier = 'q';
fmt += 2;
} else if ( *fmt == 'h' || *fmt == 'l' || *fmt == 'L'
|| *fmt == 'Z' ) {
qualifier = *fmt;
++fmt;
}
/* default base */
base = 10;
switch ( *fmt ) {
case 'c':
if ( !( flags & LEFT ) )
while ( --field_width > 0 )
*str++ = ' ';
*str++ = ( unsigned char ) va_arg( args, int );
while ( --field_width > 0 )
*str++ = ' ';
continue;
case 's':
s = va_arg( args, char * );
if ( !s )
s = "<NULL>";
len = strnlen( s, precision );
if ( !( flags & LEFT ) )
while ( len < field_width-- )
*str++ = ' ';
for ( i = 0; i < len; ++i )
*str++ = *s++;
while ( len < field_width-- )
*str++ = ' ';
continue;
case 'p':
if ( field_width == -1 ) {
field_width = 2*sizeof( void * );
flags |= ZEROPAD;
}
str = number( str,
( unsigned long ) va_arg( args, void * ), 16,
field_width, precision, flags );
continue;
case 'n':
if ( qualifier == 'l' ) {
long * ip = va_arg( args, long * );
*ip = ( str - buf );
} else if ( qualifier == 'Z' ) {
size_t * ip = va_arg( args, size_t * );
*ip = ( str - buf );
} else {
int * ip = va_arg( args, int * );
*ip = ( str - buf );
}
continue;
case '%':
*str++ = '%';
continue;
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
break;
case 'X':
flags |= LARGE;
case 'x':
base = 16;
break;
case 'd':
case 'i':
flags |= SIGN;
case 'u':
break;
default:
*str++ = '%';
if ( *fmt )
*str++ = *fmt;
else
--fmt;
continue;
}
if ( qualifier == 'l' ) {
num = va_arg( args, unsigned long );
if ( flags & SIGN )
num = ( signed long ) num;
} else if ( qualifier == 'q' ) {
num = va_arg( args, unsigned long long );
if ( flags & SIGN )
num = ( signed long long ) num;
} else if ( qualifier == 'Z' ) {
num = va_arg( args, size_t );
} else if ( qualifier == 'h' ) {
num = ( unsigned short ) va_arg( args, int );
if ( flags & SIGN )
num = ( signed short ) num;
} else {
num = va_arg( args, unsigned int );
if ( flags & SIGN )
num = ( signed int ) num;
}
str = number( str, num, base, field_width, precision, flags );
}
*str = '\0';
return str-buf;
}
412 int sprintf( char * buf, const char *fmt, ... )
{
va_list args;
int i;
va_start( args, fmt );
i=vsprintf( buf, fmt, args );
va_end( args );
return i;
}
static char sprint_buf[1024];
int
426 printf( const char *fmt, ... )
{
va_list args;
int n;
va_start( args, fmt );
n = vsprintf( sprint_buf, fmt, args );
va_end( args );
putstr( sprint_buf );
return n;
}
1 #ifndef _PPC_BOOT_STDIO_H_
#define _PPC_BOOT_STDIO_H_
#include <stdarg.h>
#define ENOMEM 12 /* Out of Memory */
#define EINVAL 22 /* Invalid argument */
#define ENOSPC 28 /* No space left on device */
10 extern void putstr( const char *ptr );
11 extern int printf( const char *fmt, ... ) __attribute__( ( format( printf, 1, 2 ) ) );
#define fprintf( fmt, args... ) printf( args )
15 extern int sprintf( char *buf, const char *fmt, ... )
__attribute__( ( format( printf, 2, 3 ) ) );
18 extern int vsprintf( char *buf, const char *fmt, va_list args );
#endif /* _PPC_BOOT_STDIO_H_ */
/* Copyright ( C ) 1991-2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or ( at your option ) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/*
* ISO C99 Standard: 7.20 General utilities <stdlib.h>
*/
#ifndef _STDLIB_H
#include <features.h>
/* Get size_t, wchar_t and NULL from <stddef.h>. */
#define __need_size_t
#ifndef __need_malloc_and_calloc
# define __need_wchar_t
# define __need_NULL
#endif
#include <stddef.h>
35 __BEGIN_DECLS
#ifndef __need_malloc_and_calloc
#define _STDLIB_H 1
#if defined __USE_XOPEN && !defined _SYS_WAIT_H
/* XPG requires a few symbols from <sys/wait.h> being defined. */
# include <bits/waitflags.h>
# include <bits/waitstatus.h>
# ifdef __USE_BSD
/* Lots of hair to allow traditional BSD use of `union wait'
as well as POSIX.1 use of `int' for the status word. */
# if defined __GNUC__ && !defined __cplusplus
# define __WAIT_INT( status ) \
( __extension__ ( { union { __typeof( status ) __in; int __i; } __u; \
__u.__in = ( status ); __u.__i; } ) )
# else
# define __WAIT_INT( status ) ( *( int * ) &( status ) )
# endif
/* This is the type of the argument to `wait'. The funky union
causes redeclarations with ether `int *' or `union wait *' to be
allowed without complaint. __WAIT_STATUS_DEFN is the type used in
the actual function definitions. */
# if !defined __GNUC__ || __GNUC__ < 2 || defined __cplusplus
# define __WAIT_STATUS void *
# define __WAIT_STATUS_DEFN void *
# else
/* This works in GCC 2.6.1 and later. */
typedef union
{
70 union wait *__uptr;
int *__iptr;
} __WAIT_STATUS __attribute__ ( ( __transparent_union__ ) );
# define __WAIT_STATUS_DEFN int *
# endif
# else /* Don't use BSD. */
# define __WAIT_INT( status ) ( status )
# define __WAIT_STATUS int *
# define __WAIT_STATUS_DEFN int *
# endif /* Use BSD. */
/* Define the macros <sys/wait.h> also would define this way. */
# define WEXITSTATUS( status ) __WEXITSTATUS( __WAIT_INT( status ) )
# define WTERMSIG( status ) __WTERMSIG( __WAIT_INT( status ) )
# define WSTOPSIG( status ) __WSTOPSIG( __WAIT_INT( status ) )
# define WIFEXITED( status ) __WIFEXITED( __WAIT_INT( status ) )
# define WIFSIGNALED( status ) __WIFSIGNALED( __WAIT_INT( status ) )
# define WIFSTOPPED( status ) __WIFSTOPPED( __WAIT_INT( status ) )
# ifdef __WIFCONTINUED
# define WIFCONTINUED( status ) __WIFCONTINUED( __WAIT_INT( status ) )
# endif
94 #endif /* X/Open and <sys/wait.h> not included. */
__BEGIN_NAMESPACE_STD
/* Returned by `div'. */
typedef struct
{
int quot; /* Quotient. */
int rem; /* Remainder. */
} div_t;
/* Returned by `ldiv'. */
#ifndef __ldiv_t_defined
typedef struct
{
long int quot; /* Quotient. */
long int rem; /* Remainder. */
} ldiv_t;
# define __ldiv_t_defined 1
#endif
__END_NAMESPACE_STD
#if defined __USE_ISOC99 && !defined __lldiv_t_defined
__BEGIN_NAMESPACE_C99
/* Returned by `lldiv'. */
__extension__ typedef struct
{
long long int quot; /* Quotient. */
long long int rem; /* Remainder. */
} lldiv_t;
# define __lldiv_t_defined 1
__END_NAMESPACE_C99
#endif
/* The largest number rand will return ( same as INT_MAX ). */
#define RAND_MAX 2147483647
/* We define these the same for all machines.
Changes from this to the outside world should be done in `_exit'. */
#define EXIT_FAILURE 1 /* Failing exit status. */
#define EXIT_SUCCESS 0 /* Successful exit status. */
/* Maximum length of a multibyte character in the current locale. */
#define MB_CUR_MAX ( __ctype_get_mb_cur_max ( ) )
extern size_t __ctype_get_mb_cur_max ( void ) __THROW __wur;
__BEGIN_NAMESPACE_STD
/* Convert a string to a floating-point number. */
extern double atof ( __const char *__nptr )
__THROW __attribute_pure__ __nonnull ( ( 1 ) ) __wur;
/* Convert a string to an integer. */
extern int atoi ( __const char *__nptr )
__THROW __attribute_pure__ __nonnull ( ( 1 ) ) __wur;
/* Convert a string to a long integer. */
extern long int atol ( __const char *__nptr )
__THROW __attribute_pure__ __nonnull ( ( 1 ) ) __wur;
__END_NAMESPACE_STD
#if defined __USE_ISOC99 || ( defined __GLIBC_HAVE_LONG_LONG && defined __USE_MISC )
__BEGIN_NAMESPACE_C99
/* Convert a string to a long long integer. */
__extension__ extern long long int atoll ( __const char *__nptr )
__THROW __attribute_pure__ __nonnull ( ( 1 ) ) __wur;
__END_NAMESPACE_C99
#endif
__BEGIN_NAMESPACE_STD
/* Convert a string to a floating-point number. */
extern double strtod ( __const char *__restrict __nptr,
char **__restrict __endptr )
__THROW __nonnull ( ( 1 ) ) __wur;
__END_NAMESPACE_STD
#ifdef __USE_ISOC99
__BEGIN_NAMESPACE_C99
/* Likewise for `float' and `long double' sizes of floating-point numbers. */
extern float strtof ( __const char *__restrict __nptr,
char **__restrict __endptr ) __THROW __nonnull ( ( 1 ) ) __wur;
extern long double strtold ( __const char *__restrict __nptr,
char **__restrict __endptr )
__THROW __nonnull ( ( 1 ) ) __wur;
__END_NAMESPACE_C99
#endif
__BEGIN_NAMESPACE_STD
/* Convert a string to a long integer. */
extern long int strtol ( __const char *__restrict __nptr,
char **__restrict __endptr, int __base )
__THROW __nonnull ( ( 1 ) ) __wur;
/* Convert a string to an unsigned long integer. */
extern unsigned long int strtoul ( __const char *__restrict __nptr,
char **__restrict __endptr, int __base )
__THROW __nonnull ( ( 1 ) ) __wur;
__END_NAMESPACE_STD
#if defined __GLIBC_HAVE_LONG_LONG && defined __USE_BSD
/* Convert a string to a quadword integer. */
__extension__
extern long long int strtoq ( __const char *__restrict __nptr,
char **__restrict __endptr, int __base )
__THROW __nonnull ( ( 1 ) ) __wur;
/* Convert a string to an unsigned quadword integer. */
__extension__
extern unsigned long long int strtouq ( __const char *__restrict __nptr,
char **__restrict __endptr, int __base )
__THROW __nonnull ( ( 1 ) ) __wur;
#endif /* GCC and use BSD. */
#if defined __USE_ISOC99 || ( defined __GLIBC_HAVE_LONG_LONG && defined __USE_MISC )
__BEGIN_NAMESPACE_C99
/* Convert a string to a quadword integer. */
__extension__
extern long long int strtoll ( __const char *__restrict __nptr,
char **__restrict __endptr, int __base )
__THROW __nonnull ( ( 1 ) ) __wur;
/* Convert a string to an unsigned quadword integer. */
__extension__
extern unsigned long long int strtoull ( __const char *__restrict __nptr,
char **__restrict __endptr, int __base )
__THROW __nonnull ( ( 1 ) ) __wur;
__END_NAMESPACE_C99
#endif /* ISO C99 or GCC and use MISC. */
#ifdef __USE_GNU
/* The concept of one static locale per category is not very well
thought out. Many applications will need to process its data using
information from several different locales. Another application is
the implementation of the internationalization handling in the
upcoming ISO C++ standard library. To support this another set of
the functions using locale data exist which have an additional
argument.
Attention: all these functions are *not* standardized in any form.
This is a proof-of-concept implementation. */
/* Structure for reentrant locale using functions. This is an
( almost ) opaque type for the user level programs. */
# include <xlocale.h>
/* Special versions of the functions above which take the locale to
use as an additional parameter. */
extern long int strtol_l ( __const char *__restrict __nptr,
char **__restrict __endptr, int __base,
__locale_t __loc ) __THROW __nonnull ( ( 1, 4 ) ) __wur;
extern unsigned long int strtoul_l ( __const char *__restrict __nptr,
char **__restrict __endptr,
int __base, __locale_t __loc )
__THROW __nonnull ( ( 1, 4 ) ) __wur;
__extension__
extern long long int strtoll_l ( __const char *__restrict __nptr,
char **__restrict __endptr, int __base,
__locale_t __loc )
__THROW __nonnull ( ( 1, 4 ) ) __wur;
__extension__
extern unsigned long long int strtoull_l ( __const char *__restrict __nptr,
char **__restrict __endptr,
int __base, __locale_t __loc )
__THROW __nonnull ( ( 1, 4 ) ) __wur;
extern double strtod_l ( __const char *__restrict __nptr,
char **__restrict __endptr, __locale_t __loc )
__THROW __nonnull ( ( 1, 3 ) ) __wur;
extern float strtof_l ( __const char *__restrict __nptr,
char **__restrict __endptr, __locale_t __loc )
__THROW __nonnull ( ( 1, 3 ) ) __wur;
extern long double strtold_l ( __const char *__restrict __nptr,
char **__restrict __endptr,
__locale_t __loc )
__THROW __nonnull ( ( 1, 3 ) ) __wur;
#endif /* GNU */
/* The internal entry points for `strtoX' take an extra flag argument
saying whether or not to parse locale-dependent number grouping. */
extern double __strtod_internal ( __const char *__restrict __nptr,
char **__restrict __endptr, int __group )
__THROW __nonnull ( ( 1 ) ) __wur;
extern float __strtof_internal ( __const char *__restrict __nptr,
char **__restrict __endptr, int __group )
__THROW __nonnull ( ( 1 ) ) __wur;
extern long double __strtold_internal ( __const char *__restrict __nptr,
char **__restrict __endptr,
int __group )
__THROW __nonnull ( ( 1 ) ) __wur;
#ifndef __strtol_internal_defined
extern long int __strtol_internal ( __const char *__restrict __nptr,
char **__restrict __endptr,
int __base, int __group )
__THROW __nonnull ( ( 1 ) ) __wur;
# define __strtol_internal_defined 1
#endif
#ifndef __strtoul_internal_defined
extern unsigned long int __strtoul_internal ( __const char *__restrict __nptr,
char **__restrict __endptr,
int __base, int __group )
__THROW __nonnull ( ( 1 ) ) __wur;
# define __strtoul_internal_defined 1
#endif
#if defined __GNUC__ || defined __USE_ISOC99
# ifndef __strtoll_internal_defined
__extension__
extern long long int __strtoll_internal ( __const char *__restrict __nptr,
char **__restrict __endptr,
int __base, int __group )
__THROW __nonnull ( ( 1 ) ) __wur;
# define __strtoll_internal_defined 1
# endif
# ifndef __strtoull_internal_defined
__extension__
extern unsigned long long int __strtoull_internal ( __const char *
__restrict __nptr,
char **__restrict __endptr,
int __base, int __group )
__THROW __nonnull ( ( 1 ) ) __wur;
# define __strtoull_internal_defined 1
# endif
#endif /* GCC */
#ifdef __USE_EXTERN_INLINES
/* Define inline functions which call the internal entry points. */
__BEGIN_NAMESPACE_STD
extern __inline double
__NTH ( strtod ( __const char *__restrict __nptr, char **__restrict __endptr ) )
{
return __strtod_internal ( __nptr, __endptr, 0 );
}
extern __inline long int
__NTH ( strtol ( __const char *__restrict __nptr, char **__restrict __endptr,
int __base ) )
{
return __strtol_internal ( __nptr, __endptr, __base, 0 );
}
extern __inline unsigned long int
__NTH ( strtoul ( __const char *__restrict __nptr, char **__restrict __endptr,
int __base ) )
{
return __strtoul_internal ( __nptr, __endptr, __base, 0 );
}
__END_NAMESPACE_STD
# ifdef __USE_ISOC99
__BEGIN_NAMESPACE_C99
extern __inline float
__NTH ( strtof ( __const char *__restrict __nptr, char **__restrict __endptr ) )
{
return __strtof_internal ( __nptr, __endptr, 0 );
}
# ifndef __LDBL_COMPAT
extern __inline long double
__NTH ( strtold ( __const char *__restrict __nptr, char **__restrict __endptr ) )
{
return __strtold_internal ( __nptr, __endptr, 0 );
}
# endif
__END_NAMESPACE_C99
# endif
# ifdef __USE_BSD
__extension__ extern __inline long long int
__NTH ( strtoq ( __const char *__restrict __nptr, char **__restrict __endptr,
int __base ) )
{
return __strtoll_internal ( __nptr, __endptr, __base, 0 );
}
__extension__ extern __inline unsigned long long int
__NTH ( strtouq ( __const char *__restrict __nptr, char **__restrict __endptr,
int __base ) )
{
return __strtoull_internal ( __nptr, __endptr, __base, 0 );
}
# endif
# if defined __USE_MISC || defined __USE_ISOC99
__BEGIN_NAMESPACE_C99
__extension__ extern __inline long long int
__NTH ( strtoll ( __const char *__restrict __nptr, char **__restrict __endptr,
int __base ) )
{
return __strtoll_internal ( __nptr, __endptr, __base, 0 );
}
__extension__ extern __inline unsigned long long int
__NTH ( strtoull ( __const char * __restrict __nptr, char **__restrict __endptr,
int __base ) )
{
return __strtoull_internal ( __nptr, __endptr, __base, 0 );
}
__END_NAMESPACE_C99
# endif
__BEGIN_NAMESPACE_STD
extern __inline double
__NTH ( atof ( __const char *__nptr ) )
{
return strtod ( __nptr, ( char ** ) NULL );
}
extern __inline int
__NTH ( atoi ( __const char *__nptr ) )
{
return ( int ) strtol ( __nptr, ( char ** ) NULL, 10 );
}
extern __inline long int
__NTH ( atol ( __const char *__nptr ) )
{
return strtol ( __nptr, ( char ** ) NULL, 10 );
}
__END_NAMESPACE_STD
# if defined __USE_MISC || defined __USE_ISOC99
__BEGIN_NAMESPACE_C99
__extension__ extern __inline long long int
__NTH ( atoll ( __const char *__nptr ) )
{
return strtoll ( __nptr, ( char ** ) NULL, 10 );
}
__END_NAMESPACE_C99
# endif
#endif /* Optimizing and Inlining. */
#if defined __USE_SVID || defined __USE_XOPEN_EXTENDED
/* Convert N to base 64 using the digits "./0-9A-Za-z", least-significant
digit first. Returns a pointer to static storage overwritten by the
next call. */
extern char *l64a ( long int __n ) __THROW __wur;
/* Read a number from a string S in base 64 as above. */
extern long int a64l ( __const char *__s )
__THROW __attribute_pure__ __nonnull ( ( 1 ) ) __wur;
#endif /* Use SVID || extended X/Open. */
#if defined __USE_SVID || defined __USE_XOPEN_EXTENDED || defined __USE_BSD
# include <sys/types.h> /* we need int32_t... */
/* These are the functions that actually do things. The `random', `srandom',
`initstate' and `setstate' functions are those from BSD Unices.
The `rand' and `srand' functions are required by the ANSI standard.
We provide both interfaces to the same random number generator. */
/* Return a random long integer between 0 and RAND_MAX inclusive. */
extern long int random ( void ) __THROW;
/* Seed the random number generator with the given number. */
extern void srandom ( unsigned int __seed ) __THROW;
/* Initialize the random number generator to use state buffer STATEBUF,
of length STATELEN, and seed it with SEED. Optimal lengths are 8, 16,
32, 64, 128 and 256, the bigger the better; values less than 8 will
cause an error and values greater than 256 will be rounded down. */
extern char *initstate ( unsigned int __seed, char *__statebuf,
size_t __statelen ) __THROW __nonnull ( ( 2 ) );
/* Switch the random number generator to state buffer STATEBUF,
which should have been previously initialized by `initstate'. */
extern char *setstate ( char *__statebuf ) __THROW __nonnull ( ( 1 ) );
# ifdef __USE_MISC
/* Reentrant versions of the `random' family of functions.
These functions all use the following data structure to contain
state, rather than global state variables. */
struct random_data
{
int32_t *fptr; /* Front pointer. */
int32_t *rptr; /* Rear pointer. */
int32_t *state; /* Array of state values. */
int rand_type; /* Type of random number generator. */
int rand_deg; /* Degree of random number generator. */
int rand_sep; /* Distance between front and rear. */
int32_t *end_ptr; /* Pointer behind state table. */
};
extern int random_r ( struct random_data *__restrict __buf,
int32_t *__restrict __result ) __THROW __nonnull ( ( 1, 2 ) );
extern int srandom_r ( unsigned int __seed, struct random_data *__buf )
__THROW __nonnull ( ( 2 ) );
extern int initstate_r ( unsigned int __seed, char *__restrict __statebuf,
size_t __statelen,
struct random_data *__restrict __buf )
__THROW __nonnull ( ( 2, 4 ) );
extern int setstate_r ( char *__restrict __statebuf,
struct random_data *__restrict __buf )
__THROW __nonnull ( ( 1, 2 ) );
# endif /* Use misc. */
#endif /* Use SVID || extended X/Open || BSD. */
__BEGIN_NAMESPACE_STD
/* Return a random integer between 0 and RAND_MAX inclusive. */
extern int rand ( void ) __THROW;
/* Seed the random number generator with the given number. */
extern void srand ( unsigned int __seed ) __THROW;
__END_NAMESPACE_STD
#ifdef __USE_POSIX
/* Reentrant interface according to POSIX.1. */
extern int rand_r ( unsigned int *__seed ) __THROW;
#endif
#if defined __USE_SVID || defined __USE_XOPEN
/* System V style 48-bit random number generator functions. */
/* Return non-negative, double-precision floating-point value in [0.0, 1.0 ). */
extern double drand48 ( void ) __THROW;
extern double erand48 ( unsigned short int __xsubi[3] ) __THROW __nonnull ( ( 1 ) );
/* Return non-negative, long integer in [0, 2^31 ). */
extern long int lrand48 ( void ) __THROW;
extern long int nrand48 ( unsigned short int __xsubi[3] )
__THROW __nonnull ( ( 1 ) );
/* Return signed, long integers in [-2^31, 2^31 ). */
extern long int mrand48 ( void ) __THROW;
extern long int jrand48 ( unsigned short int __xsubi[3] )
__THROW __nonnull ( ( 1 ) );
/* Seed random number generator. */
extern void srand48 ( long int __seedval ) __THROW;
extern unsigned short int *seed48 ( unsigned short int __seed16v[3] )
__THROW __nonnull ( ( 1 ) );
extern void lcong48 ( unsigned short int __param[7] ) __THROW __nonnull ( ( 1 ) );
# ifdef __USE_MISC
/* Data structure for communication with thread safe versions. This
type is to be regarded as opaque. It's only exported because users
have to allocate objects of this type. */
struct drand48_data
{
unsigned short int __x[3]; /* Current state. */
unsigned short int __old_x[3]; /* Old state. */
unsigned short int __c; /* Additive const. in congruential formula. */
unsigned short int __init; /* Flag for initializing. */
unsigned long long int __a; /* Factor in congruential formula. */
};
/* Return non-negative, double-precision floating-point value in [0.0, 1.0 ). */
extern int drand48_r ( struct drand48_data *__restrict __buffer,
double *__restrict __result ) __THROW __nonnull ( ( 1, 2 ) );
extern int erand48_r ( unsigned short int __xsubi[3],
struct drand48_data *__restrict __buffer,
double *__restrict __result ) __THROW __nonnull ( ( 1, 2 ) );
/* Return non-negative, long integer in [0, 2^31 ). */
extern int lrand48_r ( struct drand48_data *__restrict __buffer,
long int *__restrict __result )
__THROW __nonnull ( ( 1, 2 ) );
extern int nrand48_r ( unsigned short int __xsubi[3],
struct drand48_data *__restrict __buffer,
long int *__restrict __result )
__THROW __nonnull ( ( 1, 2 ) );
/* Return signed, long integers in [-2^31, 2^31 ). */
extern int mrand48_r ( struct drand48_data *__restrict __buffer,
long int *__restrict __result )
__THROW __nonnull ( ( 1, 2 ) );
extern int jrand48_r ( unsigned short int __xsubi[3],
struct drand48_data *__restrict __buffer,
long int *__restrict __result )
__THROW __nonnull ( ( 1, 2 ) );
/* Seed random number generator. */
extern int srand48_r ( long int __seedval, struct drand48_data *__buffer )
__THROW __nonnull ( ( 2 ) );
extern int seed48_r ( unsigned short int __seed16v[3],
struct drand48_data *__buffer ) __THROW __nonnull ( ( 1, 2 ) );
extern int lcong48_r ( unsigned short int __param[7],
struct drand48_data *__buffer )
__THROW __nonnull ( ( 1, 2 ) );
# endif /* Use misc. */
#endif /* Use SVID or X/Open. */
#endif /* don't just need malloc and calloc */
#ifndef __malloc_and_calloc_defined
# define __malloc_and_calloc_defined
__BEGIN_NAMESPACE_STD
/* Allocate SIZE bytes of memory. */
extern void *malloc ( size_t __size ) __THROW __attribute_malloc__ __wur;
/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */
extern void *calloc ( size_t __nmemb, size_t __size )
__THROW __attribute_malloc__ __wur;
__END_NAMESPACE_STD
#endif
#ifndef __need_malloc_and_calloc
__BEGIN_NAMESPACE_STD
/* Re-allocate the previously allocated block
in PTR, making the new block SIZE bytes long. */
extern void *realloc ( void *__ptr, size_t __size )
__THROW __attribute_malloc__ __attribute_warn_unused_result__;
/* Free a block allocated by `malloc', `realloc' or `calloc'. */
extern void free ( void *__ptr ) __THROW;
__END_NAMESPACE_STD
#ifdef __USE_MISC
/* Free a block. An alias for `free'. ( Sun Unices ). */
extern void cfree ( void *__ptr ) __THROW;
#endif /* Use misc. */
#if defined __USE_GNU || defined __USE_BSD || defined __USE_MISC
# include <alloca.h>
#endif /* Use GNU, BSD, or misc. */
#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
/* Allocate SIZE bytes on a page boundary. The storage cannot be freed. */
extern void *valloc ( size_t __size ) __THROW __attribute_malloc__ __wur;
#endif
#ifdef __USE_XOPEN2K
/* Allocate memory of SIZE bytes with an alignment of ALIGNMENT. */
extern int posix_memalign ( void **__memptr, size_t __alignment, size_t __size )
__THROW __nonnull ( ( 1 ) ) __wur;
#endif
__BEGIN_NAMESPACE_STD
/* Abort execution and generate a core-dump. */
extern void abort ( void ) __THROW __attribute__ ( ( __noreturn__ ) );
/* Register a function to be called when `exit' is called. */
extern int atexit ( void ( *__func ) ( void ) ) __THROW __nonnull ( ( 1 ) );
__END_NAMESPACE_STD
#ifdef __USE_MISC
/* Register a function to be called with the status
given to `exit' and the given argument. */
extern int on_exit ( void ( *__func ) ( int __status, void *__arg ), void *__arg )
__THROW __nonnull ( ( 1 ) );
#endif
__BEGIN_NAMESPACE_STD
/* Call all functions registered with `atexit' and `on_exit',
in the reverse of the order in which they were registered
perform stdio cleanup, and terminate program execution with STATUS. */
extern void exit ( int __status ) __THROW __attribute__ ( ( __noreturn__ ) );
__END_NAMESPACE_STD
#ifdef __USE_ISOC99
__BEGIN_NAMESPACE_C99
/* Terminate the program with STATUS without calling any of the
functions registered with `atexit' or `on_exit'. */
extern void _Exit ( int __status ) __THROW __attribute__ ( ( __noreturn__ ) );
__END_NAMESPACE_C99
#endif
__BEGIN_NAMESPACE_STD
/* Return the value of envariable NAME, or NULL if it doesn't exist. */
extern char *getenv ( __const char *__name ) __THROW __nonnull ( ( 1 ) ) __wur;
__END_NAMESPACE_STD
/* This function is similar to the above but returns NULL if the
programs is running with SUID or SGID enabled. */
extern char *__secure_getenv ( __const char *__name )
__THROW __nonnull ( ( 1 ) ) __wur;
#if defined __USE_SVID || defined __USE_XOPEN
/* The SVID says this is in <stdio.h>, but this seems a better place. */
/* Put STRING, which is of the form "NAME=VALUE", in the environment.
If there is no `=', remove NAME from the environment. */
extern int putenv ( char *__string ) __THROW __nonnull ( ( 1 ) );
#endif
#if defined __USE_BSD || defined __USE_XOPEN2K
/* Set NAME to VALUE in the environment.
If REPLACE is nonzero, overwrite an existing value. */
extern int setenv ( __const char *__name, __const char *__value, int __replace )
__THROW __nonnull ( ( 2 ) );
/* Remove the variable NAME from the environment. */
extern int unsetenv ( __const char *__name ) __THROW;
#endif
#ifdef __USE_MISC
/* The `clearenv' was planned to be added to POSIX.1 but probably
never made it. Nevertheless the POSIX.9 standard ( POSIX bindings
for Fortran 77 ) requires this function. */
extern int clearenv ( void ) __THROW;
#endif
#if defined __USE_MISC || defined __USE_XOPEN_EXTENDED
/* Generate a unique temporary file name from TEMPLATE.
The last six characters of TEMPLATE must be "XXXXXX";
they are replaced with a string that makes the file name unique.
Returns TEMPLATE, or a null pointer if it cannot get a unique file name. */
extern char *mktemp ( char *__template ) __THROW __nonnull ( ( 1 ) ) __wur;
/* Generate a unique temporary file name from TEMPLATE.
The last six characters of TEMPLATE must be "XXXXXX";
they are replaced with a string that makes the filename unique.
Returns a file descriptor open on the file for reading and writing,
or -1 if it cannot create a uniquely-named file.
This function is a possible cancellation points and therefore not
marked with __THROW. */
# ifndef __USE_FILE_OFFSET64
extern int mkstemp ( char *__template ) __nonnull ( ( 1 ) ) __wur;
# else
# ifdef __REDIRECT
extern int __REDIRECT ( mkstemp, ( char *__template ), mkstemp64 )
__nonnull ( ( 1 ) ) __wur;
# else
# define mkstemp mkstemp64
# endif
# endif
# ifdef __USE_LARGEFILE64
extern int mkstemp64 ( char *__template ) __nonnull ( ( 1 ) ) __wur;
# endif
#endif
#ifdef __USE_BSD
/* Create a unique temporary directory from TEMPLATE.
The last six characters of TEMPLATE must be "XXXXXX";
they are replaced with a string that makes the directory name unique.
Returns TEMPLATE, or a null pointer if it cannot get a unique name.
The directory is created mode 700. */
extern char *mkdtemp ( char *__template ) __THROW __nonnull ( ( 1 ) ) __wur;
#endif
__BEGIN_NAMESPACE_STD
/* Execute the given line as a shell command.
This function is a cancellation point and therefore not marked with
__THROW. */
extern int system ( __const char *__command ) __wur;
__END_NAMESPACE_STD
#ifdef __USE_GNU
/* Return a malloc'd string containing the canonical absolute name of the
named file. The last file name component need not exist, and may be a
symlink to a nonexistent file. */
extern char *canonicalize_file_name ( __const char *__name )
__THROW __nonnull ( ( 1 ) ) __wur;
#endif
#if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
/* Return the canonical absolute name of file NAME. The last file name
component need not exist, and may be a symlink to a nonexistent file.
If RESOLVED is null, the result is malloc'd; otherwise, if the canonical
name is PATH_MAX chars or more, returns null with `errno' set to
ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars, returns the
name in RESOLVED. */
extern char *realpath ( __const char *__restrict __name,
char *__restrict __resolved ) __THROW __wur;
#endif
/* Shorthand for type of comparison functions. */
#ifndef __COMPAR_FN_T
# define __COMPAR_FN_T
typedef int ( *__compar_fn_t ) ( __const void *, __const void * );
# ifdef __USE_GNU
typedef __compar_fn_t comparison_fn_t;
# endif
#endif
__BEGIN_NAMESPACE_STD
/* Do a binary search for KEY in BASE, which consists of NMEMB elements
of SIZE bytes each, using COMPAR to perform the comparisons. */
extern void *bsearch ( __const void *__key, __const void *__base,
size_t __nmemb, size_t __size, __compar_fn_t __compar )
__nonnull ( ( 1, 2, 5 ) ) __wur;
/* Sort NMEMB elements of BASE, of SIZE bytes each,
using COMPAR to perform the comparisons. */
extern void qsort ( void *__base, size_t __nmemb, size_t __size,
__compar_fn_t __compar ) __nonnull ( ( 1, 4 ) );
/* Return the absolute value of X. */
extern int abs ( int __x ) __THROW __attribute__ ( ( __const__ ) ) __wur;
extern long int labs ( long int __x ) __THROW __attribute__ ( ( __const__ ) ) __wur;
__END_NAMESPACE_STD
#ifdef __USE_ISOC99
__extension__ extern long long int llabs ( long long int __x )
__THROW __attribute__ ( ( __const__ ) ) __wur;
#endif
__BEGIN_NAMESPACE_STD
/* Return the `div_t', `ldiv_t' or `lldiv_t' representation
of the value of NUMER over DENOM. */
/* GCC may have built-ins for these someday. */
extern div_t div ( int __numer, int __denom )
__THROW __attribute__ ( ( __const__ ) ) __wur;
extern ldiv_t ldiv ( long int __numer, long int __denom )
__THROW __attribute__ ( ( __const__ ) ) __wur;
__END_NAMESPACE_STD
#ifdef __USE_ISOC99
__BEGIN_NAMESPACE_C99
__extension__ extern lldiv_t lldiv ( long long int __numer,
long long int __denom )
__THROW __attribute__ ( ( __const__ ) ) __wur;
__END_NAMESPACE_C99
#endif
#if defined __USE_SVID || defined __USE_XOPEN_EXTENDED
/* Convert floating point numbers to strings. The returned values are
valid only until another call to the same function. */
/* Convert VALUE to a string with NDIGIT digits and return a pointer to
this. Set *DECPT with the position of the decimal character and *SIGN
with the sign of the number. */
extern char *ecvt ( double __value, int __ndigit, int *__restrict __decpt,
int *__restrict __sign ) __THROW __nonnull ( ( 3, 4 ) ) __wur;
/* Convert VALUE to a string rounded to NDIGIT decimal digits. Set *DECPT
with the position of the decimal character and *SIGN with the sign of
the number. */
extern char *fcvt ( double __value, int __ndigit, int *__restrict __decpt,
int *__restrict __sign ) __THROW __nonnull ( ( 3, 4 ) ) __wur;
/* If possible convert VALUE to a string with NDIGIT significant digits.
Otherwise use exponential representation. The resulting string will
be written to BUF. */
extern char *gcvt ( double __value, int __ndigit, char *__buf )
__THROW __nonnull ( ( 3 ) ) __wur;
# ifdef __USE_MISC
/* Long double versions of above functions. */
extern char *qecvt ( long double __value, int __ndigit,
int *__restrict __decpt, int *__restrict __sign )
__THROW __nonnull ( ( 3, 4 ) ) __wur;
extern char *qfcvt ( long double __value, int __ndigit,
int *__restrict __decpt, int *__restrict __sign )
__THROW __nonnull ( ( 3, 4 ) ) __wur;
extern char *qgcvt ( long double __value, int __ndigit, char *__buf )
__THROW __nonnull ( ( 3 ) ) __wur;
/* Reentrant version of the functions above which provide their own
buffers. */
extern int ecvt_r ( double __value, int __ndigit, int *__restrict __decpt,
int *__restrict __sign, char *__restrict __buf,
size_t __len ) __THROW __nonnull ( ( 3, 4, 5 ) );
extern int fcvt_r ( double __value, int __ndigit, int *__restrict __decpt,
int *__restrict __sign, char *__restrict __buf,
size_t __len ) __THROW __nonnull ( ( 3, 4, 5 ) );
extern int qecvt_r ( long double __value, int __ndigit,
int *__restrict __decpt, int *__restrict __sign,
char *__restrict __buf, size_t __len )
__THROW __nonnull ( ( 3, 4, 5 ) );
extern int qfcvt_r ( long double __value, int __ndigit,
int *__restrict __decpt, int *__restrict __sign,
char *__restrict __buf, size_t __len )
__THROW __nonnull ( ( 3, 4, 5 ) );
# endif /* misc */
#endif /* use MISC || use X/Open Unix */
__BEGIN_NAMESPACE_STD
/* Return the length of the multibyte character
in S, which is no longer than N. */
extern int mblen ( __const char *__s, size_t __n ) __THROW __wur;
/* Return the length of the given multibyte character,
putting its `wchar_t' representation in *PWC. */
extern int mbtowc ( wchar_t *__restrict __pwc,
__const char *__restrict __s, size_t __n ) __THROW __wur;
/* Put the multibyte character represented
by WCHAR in S, returning its length. */
extern int wctomb ( char *__s, wchar_t __wchar ) __THROW __wur;
/* Convert a multibyte string to a wide char string. */
extern size_t mbstowcs ( wchar_t *__restrict __pwcs,
__const char *__restrict __s, size_t __n ) __THROW;
/* Convert a wide char string to multibyte string. */
extern size_t wcstombs ( char *__restrict __s,
__const wchar_t *__restrict __pwcs, size_t __n )
__THROW;
__END_NAMESPACE_STD
#ifdef __USE_SVID
/* Determine whether the string value of RESPONSE matches the affirmation
or negative response expression as specified by the LC_MESSAGES category
in the program's current locale. Returns 1 if affirmative, 0 if
negative, and -1 if not matching. */
extern int rpmatch ( __const char *__response ) __THROW __nonnull ( ( 1 ) ) __wur;
#endif
#ifdef __USE_XOPEN_EXTENDED
/* Parse comma separated suboption from *OPTIONP and match against
strings in TOKENS. If found return index and set *VALUEP to
optional value introduced by an equal sign. If the suboption is
not part of TOKENS return in *VALUEP beginning of unknown
suboption. On exit *OPTIONP is set to the beginning of the next
token or at the terminating NUL character. */
extern int getsubopt ( char **__restrict __optionp,
char *__const *__restrict __tokens,
char **__restrict __valuep )
__THROW __nonnull ( ( 1, 2, 3 ) ) __wur;
#endif
#ifdef __USE_XOPEN
/* Setup DES tables according KEY. */
extern void setkey ( __const char *__key ) __THROW __nonnull ( ( 1 ) );
#endif
/* X/Open pseudo terminal handling. */
#ifdef __USE_XOPEN2K
/* Return a master pseudo-terminal handle. */
extern int posix_openpt ( int __oflag ) __wur;
#endif
#ifdef __USE_XOPEN
/* The next four functions all take a master pseudo-tty fd and
perform an operation on the associated slave: */
/* Chown the slave to the calling user. */
extern int grantpt ( int __fd ) __THROW;
/* Release an internal lock so the slave can be opened.
Call after grantpt( ). */
extern int unlockpt ( int __fd ) __THROW;
/* Return the pathname of the pseudo terminal slave assoicated with
the master FD is open on, or NULL on errors.
The returned storage is good until the next call to this function. */
extern char *ptsname ( int __fd ) __THROW __wur;
#endif
#ifdef __USE_GNU
/* Store at most BUFLEN characters of the pathname of the slave pseudo
terminal associated with the master FD is open on in BUF.
Return 0 on success, otherwise an error number. */
extern int ptsname_r ( int __fd, char *__buf, size_t __buflen )
__THROW __nonnull ( ( 2 ) );
/* Open a master pseudo terminal and return its file descriptor. */
extern int getpt ( void );
#endif
#ifdef __USE_BSD
/* Put the 1 minute, 5 minute and 15 minute load averages into the first
NELEM elements of LOADAVG. Return the number written ( never more than
three, but may be less than NELEM ), or -1 if an error occurred. */
extern int getloadavg ( double __loadavg[], int __nelem )
__THROW __nonnull ( ( 1 ) );
#endif
/* Define some macros helping to catch buffer overflows. */
#if __USE_FORTIFY_LEVEL > 0 && !defined __cplusplus
# include <bits/stdlib.h>
#endif
#ifdef __LDBL_COMPAT
# include <bits/stdlib-ldbl.h>
#endif
#endif /* don't just need malloc and calloc */
#undef __need_malloc_and_calloc
__END_DECLS
#endif /* stdlib.h */
1 /*
* linux/lib/string.c
*
* Copyright ( C ) 1991, 1992 Linus Torvalds
*/
/*
* stupid library routines.. The optimized versions should generally be found
* as inline code in <asm-xx/string.h>
*
* These are buggy as well..
*
* * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
* - Added strsep( ) which will replace strtok( ) soon ( because strsep( ) is
* reentrant and should be faster ). Use only strsep( ) in new code, please.
*
* * Sat Feb 09 2002, Jason Thomas <jason@topic.com.au>,
* Matthew Hawkins <matt@mh.dropbear.id.au>
* - Kissed strtok( ) goodbye
*/
#include <linux/types.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/module.h>
#ifndef __HAVE_ARCH_STRNICMP
/**
* strnicmp - Case insensitive, length-limited string comparison
* @s1: One string
* @s2: The other string
* @len: the maximum number of characters to compare
*/
34 int strnicmp( const char *s1, const char *s2, size_t len )
{
/* Yes, Virginia, it had better be unsigned */
unsigned char c1, c2;
c1 = c2 = 0;
if ( len ) {
do {
c1 = *s1;
c2 = *s2;
s1++;
s2++;
if ( !c1 )
break;
if ( !c2 )
break;
if ( c1 == c2 )
continue;
c1 = tolower( c1 );
c2 = tolower( c2 );
if ( c1 != c2 )
break;
} while ( --len );
}
return ( int )c1 - ( int )c2;
}
60 EXPORT_SYMBOL( strnicmp );
#endif
#ifndef __HAVE_ARCH_STRCASECMP
64 int strcasecmp( const char *s1, const char *s2 )
{
int c1, c2;
do {
c1 = tolower( *s1++ );
c2 = tolower( *s2++ );
} while ( c1 == c2 && c1 != 0 );
return c1 - c2;
}
74 EXPORT_SYMBOL( strcasecmp );
#endif
#ifndef __HAVE_ARCH_STRNCASECMP
78 int strncasecmp( const char *s1, const char *s2, size_t n )
{
int c1, c2;
do {
c1 = tolower( *s1++ );
c2 = tolower( *s2++ );
} while ( ( --n > 0 ) && c1 == c2 && c1 != 0 );
return c1 - c2;
}
88 EXPORT_SYMBOL( strncasecmp );
#endif
#ifndef __HAVE_ARCH_STRCPY
/**
* strcpy - Copy a %NUL terminated string
* @dest: Where to copy the string to
* @src: Where to copy the string from
*/
#undef strcpy
98 char *strcpy( char *dest, const char *src )
{
char *tmp = dest;
while ( ( *dest++ = *src++ ) != '\0' )
/* nothing */;
return tmp;
}
106 EXPORT_SYMBOL( strcpy );
#endif
#ifndef __HAVE_ARCH_STRNCPY
/**
* strncpy - Copy a length-limited, %NUL-terminated string
* @dest: Where to copy the string to
* @src: Where to copy the string from
* @count: The maximum number of bytes to copy
*
* The result is not %NUL-terminated if the source exceeds
* @count bytes.
*
* In the case where the length of @src is less than that of
* count, the remainder of @dest will be padded with %NUL.
*
*/
123 char *strncpy( char *dest, const char *src, size_t count )
{
char *tmp = dest;
while ( count ) {
if ( ( *tmp = *src ) != 0 )
src++;
tmp++;
count--;
}
return dest;
}
135 EXPORT_SYMBOL( strncpy );
#endif
#ifndef __HAVE_ARCH_STRLCPY
/**
* strlcpy - Copy a %NUL terminated string into a sized buffer
* @dest: Where to copy the string to
* @src: Where to copy the string from
* @size: size of destination buffer
*
* Compatible with *BSD: the result is always a valid
* NUL-terminated string that fits in the buffer ( unless,
* of course, the buffer size is zero ). It does not pad
* out the result like strncpy( ) does.
*/
150 size_t strlcpy( char *dest, const char *src, size_t size )
{
size_t ret = strlen( src );
if ( size ) {
size_t len = ( ret >= size ) ? size - 1 : ret;
memcpy( dest, src, len );
dest[len] = '\0';
}
return ret;
}
161 EXPORT_SYMBOL( strlcpy );
#endif
#ifndef __HAVE_ARCH_STRCAT
/**
* strcat - Append one %NUL-terminated string to another
* @dest: The string to be appended to
* @src: The string to append to it
*/
#undef strcat
171 char *strcat( char *dest, const char *src )
{
char *tmp = dest;
while ( *dest )
dest++;
while ( ( *dest++ = *src++ ) != '\0' )
;
return tmp;
}
181 EXPORT_SYMBOL( strcat );
#endif
#ifndef __HAVE_ARCH_STRNCAT
/**
* strncat - Append a length-limited, %NUL-terminated string to another
* @dest: The string to be appended to
* @src: The string to append to it
* @count: The maximum numbers of bytes to copy
*
* Note that in contrast to strncpy( ), strncat( ) ensures the result is
* terminated.
*/
194 char *strncat( char *dest, const char *src, size_t count )
{
char *tmp = dest;
if ( count ) {
while ( *dest )
dest++;
while ( ( *dest++ = *src++ ) != 0 ) {
if ( --count == 0 ) {
*dest = '\0';
break;
}
}
}
return tmp;
}
210 EXPORT_SYMBOL( strncat );
#endif
#ifndef __HAVE_ARCH_STRLCAT
/**
* strlcat - Append a length-limited, %NUL-terminated string to another
* @dest: The string to be appended to
* @src: The string to append to it
* @count: The size of the destination buffer.
*/
220 size_t strlcat( char *dest, const char *src, size_t count )
{
size_t dsize = strlen( dest );
size_t len = strlen( src );
size_t res = dsize + len;
/* This would be a bug */
BUG_ON( dsize >= count );
dest += dsize;
count -= dsize;
if ( len >= count )
len = count-1;
memcpy( dest, src, len );
dest[len] = 0;
return res;
}
237 EXPORT_SYMBOL( strlcat );
#endif
#ifndef __HAVE_ARCH_STRCMP
/**
* strcmp - Compare two strings
* @cs: One string
* @ct: Another string
*/
#undef strcmp
247 int strcmp( const char *cs, const char *ct )
{
signed char __res;
while ( 1 ) {
if ( ( __res = *cs - *ct++ ) != 0 || !*cs++ )
break;
}
return __res;
}
257 EXPORT_SYMBOL( strcmp );
#endif
#ifndef __HAVE_ARCH_STRNCMP
/**
* strncmp - Compare two length-limited strings
* @cs: One string
* @ct: Another string
* @count: The maximum number of bytes to compare
*/
267 int strncmp( const char *cs, const char *ct, size_t count )
{
signed char __res = 0;
while ( count ) {
if ( ( __res = *cs - *ct++ ) != 0 || !*cs++ )
break;
count--;
}
return __res;
}
278 EXPORT_SYMBOL( strncmp );
#endif
#ifndef __HAVE_ARCH_STRCHR
/**
* strchr - Find the first occurrence of a character in a string
* @s: The string to be searched
* @c: The character to search for
*/
287 char *strchr( const char *s, int c )
{
for ( ; *s != ( char )c; ++s )
if ( *s == '\0' )
return NULL;
return ( char * )s;
}
294 EXPORT_SYMBOL( strchr );
#endif
#ifndef __HAVE_ARCH_STRRCHR
/**
* strrchr - Find the last occurrence of a character in a string
* @s: The string to be searched
* @c: The character to search for
*/
303 char *strrchr( const char *s, int c )
{
const char *p = s + strlen( s );
do {
if ( *p == ( char )c )
return ( char * )p;
} while ( --p >= s );
return NULL;
}
312 EXPORT_SYMBOL( strrchr );
#endif
#ifndef __HAVE_ARCH_STRNCHR
/**
* strnchr - Find a character in a length limited string
* @s: The string to be searched
* @count: The number of characters to be searched
* @c: The character to search for
*/
322 char *strnchr( const char *s, size_t count, int c )
{
for ( ; count-- && *s != '\0'; ++s )
if ( *s == ( char )c )
return ( char * )s;
return NULL;
}
329 EXPORT_SYMBOL( strnchr );
#endif
/**
* strstrip - Removes leading and trailing whitespace from @s.
* @s: The string to be stripped.
*
* Note that the first trailing whitespace is replaced with a %NUL-terminator
* in the given string @s. Returns a pointer to the first non-whitespace
* character in @s.
*/
340 char *strstrip( char *s )
{
size_t size;
char *end;
size = strlen( s );
if ( !size )
return s;
end = s + size - 1;
while ( end >= s && isspace( *end ) )
end--;
*( end + 1 ) = '\0';
while ( *s && isspace( *s ) )
s++;
return s;
}
360 EXPORT_SYMBOL( strstrip );
#ifndef __HAVE_ARCH_STRLEN
/**
* strlen - Find the length of a string
* @s: The string to be sized
*/
367 size_t strlen( const char *s )
{
const char *sc;
for ( sc = s; *sc != '\0'; ++sc )
/* nothing */;
return sc - s;
}
375 EXPORT_SYMBOL( strlen );
#endif
#ifndef __HAVE_ARCH_STRNLEN
/**
* strnlen - Find the length of a length-limited string
* @s: The string to be sized
* @count: The maximum number of bytes to search
*/
384 size_t strnlen( const char *s, size_t count )
{
const char *sc;
for ( sc = s; count-- && *sc != '\0'; ++sc )
/* nothing */;
return sc - s;
}
392 EXPORT_SYMBOL( strnlen );
#endif
#ifndef __HAVE_ARCH_STRSPN
/**
* strspn - Calculate the length of the initial substring of @s which only contain letters in @accept
* @s: The string to be searched
* @accept: The string to search for
*/
401 size_t strspn( const char *s, const char *accept )
{
const char *p;
const char *a;
size_t count = 0;
for ( p = s; *p != '\0'; ++p ) {
for ( a = accept; *a != '\0'; ++a ) {
if ( *p == *a )
break;
}
if ( *a == '\0' )
return count;
++count;
}
return count;
}
419 EXPORT_SYMBOL( strspn );
#endif
#ifndef __HAVE_ARCH_STRCSPN
/**
* strcspn - Calculate the length of the initial substring of @s which does not contain letters in @reject
* @s: The string to be searched
* @reject: The string to avoid
*/
428 size_t strcspn( const char *s, const char *reject )
{
const char *p;
const char *r;
size_t count = 0;
for ( p = s; *p != '\0'; ++p ) {
for ( r = reject; *r != '\0'; ++r ) {
if ( *p == *r )
return count;
}
++count;
}
return count;
}
443 EXPORT_SYMBOL( strcspn );
#endif
#ifndef __HAVE_ARCH_STRPBRK
/**
* strpbrk - Find the first occurrence of a set of characters
* @cs: The string to be searched
* @ct: The characters to search for
*/
452 char *strpbrk( const char *cs, const char *ct )
{
const char *sc1, *sc2;
for ( sc1 = cs; *sc1 != '\0'; ++sc1 ) {
for ( sc2 = ct; *sc2 != '\0'; ++sc2 ) {
if ( *sc1 == *sc2 )
return ( char * )sc1;
}
}
return NULL;
}
464 EXPORT_SYMBOL( strpbrk );
#endif
#ifndef __HAVE_ARCH_STRSEP
/**
* strsep - Split a string into tokens
* @s: The string to be searched
* @ct: The characters to search for
*
* strsep( ) updates @s to point after the token, ready for the next call.
*
* It returns empty tokens, too, behaving exactly like the libc function
* of that name. In fact, it was stolen from glibc2 and de-fancy-fied.
* Same semantics, slimmer shape. ; )
*/
479 char *strsep( char **s, const char *ct )
{
char *sbegin = *s;
char *end;
if ( sbegin == NULL )
return NULL;
end = strpbrk( sbegin, ct );
if ( end )
*end++ = '\0';
*s = end;
return sbegin;
}
493 EXPORT_SYMBOL( strsep );
#endif
#ifndef __HAVE_ARCH_MEMSET
/**
* memset - Fill a region of memory with the given value
* @s: Pointer to the start of the area.
* @c: The byte to fill the area with
* @count: The size of the area.
*
* Do not use memset( ) to access IO space, use memset_io( ) instead.
*/
505 void *memset( void *s, int c, size_t count )
{
char *xs = s;
while ( count-- )
*xs++ = c;
return s;
}
513 EXPORT_SYMBOL( memset );
#endif
#ifndef __HAVE_ARCH_MEMCPY
/**
* memcpy - Copy one area of memory to another
* @dest: Where to copy to
* @src: Where to copy from
* @count: The size of the area.
*
* You should not use this function to access IO space, use memcpy_toio( )
* or memcpy_fromio( ) instead.
*/
526 void *memcpy( void *dest, const void *src, size_t count )
{
char *tmp = dest;
const char *s = src;
while ( count-- )
*tmp++ = *s++;
return dest;
}
535 EXPORT_SYMBOL( memcpy );
#endif
#ifndef __HAVE_ARCH_MEMMOVE
/**
* memmove - Copy one area of memory to another
* @dest: Where to copy to
* @src: Where to copy from
* @count: The size of the area.
*
* Unlike memcpy( ), memmove( ) copes with overlapping areas.
*/
547 void *memmove( void *dest, const void *src, size_t count )
{
char *tmp;
const char *s;
if ( dest <= src ) {
tmp = dest;
s = src;
while ( count-- )
*tmp++ = *s++;
} else {
tmp = dest;
tmp += count;
s = src;
s += count;
while ( count-- )
*--tmp = *--s;
}
return dest;
}
567 EXPORT_SYMBOL( memmove );
#endif
#ifndef __HAVE_ARCH_MEMCMP
/**
* memcmp - Compare two areas of memory
* @cs: One area of memory
* @ct: Another area of memory
* @count: The size of the area.
*/
#undef memcmp
578 int memcmp( const void *cs, const void *ct, size_t count )
{
const unsigned char *su1, *su2;
int res = 0;
for ( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count-- )
if ( ( res = *su1 - *su2 ) != 0 )
break;
return res;
}
588 EXPORT_SYMBOL( memcmp );
#endif
#ifndef __HAVE_ARCH_MEMSCAN
/**
* memscan - Find a character in an area of memory.
* @addr: The memory area
* @c: The byte to search for
* @size: The size of the area.
*
* returns the address of the first occurrence of @c, or 1 byte past
* the area if @c is not found
*/
601 void *memscan( void *addr, int c, size_t size )
{
unsigned char *p = addr;
while ( size ) {
if ( *p == c )
return ( void * )p;
p++;
size--;
}
return ( void * )p;
}
613 EXPORT_SYMBOL( memscan );
#endif
#ifndef __HAVE_ARCH_STRSTR
/**
* strstr - Find the first substring in a %NUL terminated string
* @s1: The string to be searched
* @s2: The string to search for
*/
622 char *strstr( const char *s1, const char *s2 )
{
int l1, l2;
l2 = strlen( s2 );
if ( !l2 )
return ( char * )s1;
l1 = strlen( s1 );
while ( l1 >= l2 ) {
l1--;
if ( !memcmp( s1, s2, l2 ) )
return ( char * )s1;
s1++;
}
return NULL;
}
638 EXPORT_SYMBOL( strstr );
#endif
#ifndef __HAVE_ARCH_MEMCHR
/**
* memchr - Find a character in an area of memory.
* @s: The memory area
* @c: The byte to search for
* @n: The size of the area.
*
* returns the address of the first occurrence of @c, or %NULL
* if @c is not found
*/
651 void *memchr( const void *s, int c, size_t n )
{
const unsigned char *p = s;
while ( n-- != 0 ) {
if ( ( unsigned char )c == *p++ ) {
return ( void * )( p - 1 );
}
}
return NULL;
}
661 EXPORT_SYMBOL( memchr );
#endif
1 /* Copyright ( C ) 1991-1993, 1995-2003, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or ( at your option ) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/*
* ISO C99 Standard: 7.21 String handling <string.h>
*/
#ifndef _STRING_H
#define _STRING_H 1
#include <features.h>
28 __BEGIN_DECLS
/* Get size_t and NULL from <stddef.h>. */
#define __need_size_t
#define __need_NULL
#include <stddef.h>
__BEGIN_NAMESPACE_STD
/* Copy N bytes of SRC to DEST. */
extern void *memcpy ( void *__restrict __dest,
__const void *__restrict __src, size_t __n )
__THROW __nonnull ( ( 1, 2 ) );
/* Copy N bytes of SRC to DEST, guaranteeing
correct behavior for overlapping strings. */
43 extern void *memmove ( void *__dest, __const void *__src, size_t __n )
44 __THROW __nonnull ( ( 1, 2 ) );
45 __END_NAMESPACE_STD
/* Copy no more than N bytes of SRC to DEST, stopping when C is found.
Return the position in DEST one byte past where C was copied,
or NULL if C was not found in the first N bytes of SRC. */
#if defined __USE_SVID || defined __USE_BSD || defined __USE_XOPEN
extern void *memccpy ( void *__restrict __dest, __const void *__restrict __src,
int __c, size_t __n )
__THROW __nonnull ( ( 1, 2 ) );
#endif /* SVID. */
__BEGIN_NAMESPACE_STD
/* Set N bytes of S to C. */
59 extern void *memset ( void *__s, int __c, size_t __n ) __THROW __nonnull ( ( 1 ) );
/* Compare N bytes of S1 and S2. */
62 extern int memcmp ( __const void *__s1, __const void *__s2, size_t __n )
__THROW __attribute_pure__ __nonnull ( ( 1, 2 ) );
/* Search N bytes of S for C. */
66 extern void *memchr ( __const void *__s, int __c, size_t __n )
__THROW __attribute_pure__ __nonnull ( ( 1 ) );
68 __END_NAMESPACE_STD
#ifdef __USE_GNU
/* Search in S for C. This is similar to `memchr' but there is no
length limit. */
extern void *rawmemchr ( __const void *__s, int __c )
__THROW __attribute_pure__ __nonnull ( ( 1 ) );
/* Search N bytes of S for the final occurrence of C. */
77 extern void *memrchr ( __const void *__s, int __c, size_t __n )
78 __THROW __attribute_pure__ __nonnull ( ( 1 ) );
#endif
82 __BEGIN_NAMESPACE_STD
/* Copy SRC to DEST. */
extern char *strcpy ( char *__restrict __dest, __const char *__restrict __src )
__THROW __nonnull ( ( 1, 2 ) );
/* Copy no more than N characters of SRC to DEST. */
87 extern char *strncpy ( char *__restrict __dest,
__const char *__restrict __src, size_t __n )
__THROW __nonnull ( ( 1, 2 ) );
/* Append SRC onto DEST. */
92 extern char *strcat ( char *__restrict __dest, __const char *__restrict __src )
__THROW __nonnull ( ( 1, 2 ) );
/* Append no more than N characters from SRC onto DEST. */
95 extern char *strncat ( char *__restrict __dest, __const char *__restrict __src,
size_t __n ) __THROW __nonnull ( ( 1, 2 ) );
/* Compare S1 and S2. */
99 extern int strcmp ( __const char *__s1, __const char *__s2 )
__THROW __attribute_pure__ __nonnull ( ( 1, 2 ) );
/* Compare N characters of S1 and S2. */
102 extern int strncmp ( __const char *__s1, __const char *__s2, size_t __n )
__THROW __attribute_pure__ __nonnull ( ( 1, 2 ) );
/* Compare the collated forms of S1 and S2. */
106 extern int strcoll ( __const char *__s1, __const char *__s2 )
__THROW __attribute_pure__ __nonnull ( ( 1, 2 ) );
/* Put a transformation of SRC into no more than N bytes of DEST. */
109 extern size_t strxfrm ( char *__restrict __dest,
__const char *__restrict __src, size_t __n )
__THROW __nonnull ( ( 2 ) );
112 __END_NAMESPACE_STD
#ifdef __USE_GNU
/* The following functions are equivalent to the both above but they
take the locale they use for the collation as an extra argument.
This is not standardsized but something like will come. */
# include <xlocale.h>
/* Compare the collated forms of S1 and S2 using rules from L. */
extern int strcoll_l ( __const char *__s1, __const char *__s2, __locale_t __l )
__THROW __attribute_pure__ __nonnull ( ( 1, 2, 3 ) );
/* Put a transformation of SRC into no more than N bytes of DEST. */
124 extern size_t strxfrm_l ( char *__dest, __const char *__src, size_t __n,
125 __locale_t __l ) __THROW __nonnull ( ( 2, 4 ) );
#endif
#if defined __USE_SVID || defined __USE_BSD || defined __USE_XOPEN_EXTENDED
/* Duplicate S, returning an identical malloc'd string. */
130 extern char *strdup ( __const char *__s )
131 __THROW __attribute_malloc__ __nonnull ( ( 1 ) );
#endif
/* Return a malloc'd copy of at most N bytes of STRING. The
resultant string is terminated even if no null terminator
appears before STRING[N]. */
#if defined __USE_GNU
138 extern char *strndup ( __const char *__string, size_t __n )
139 __THROW __attribute_malloc__ __nonnull ( ( 1 ) );
#endif
#if defined __USE_GNU && defined __GNUC__
/* Duplicate S, returning an identical alloca'd string. */
# define strdupa( s ) \
( __extension__ \
( { \
__const char *__old = ( s ); \
size_t __len = strlen ( __old ) + 1; \
char *__new = ( char * ) __builtin_alloca ( __len ); \
150 ( char * ) memcpy ( __new, __old, __len ); \
} ) )
/* Return an alloca'd copy of at most N bytes of string. */
# define strndupa( s, n ) \
155 ( __extension__ \
( { \
157 __const char *__old = ( s ); \
size_t __len = strnlen ( __old, ( n ) ); \
char *__new = ( char * ) __builtin_alloca ( __len + 1 ); \
__new[__len] = '\0'; \
( char * ) memcpy ( __new, __old, __len ); \
} ) )
#endif
__BEGIN_NAMESPACE_STD
166 /* Find the first occurrence of C in S. */
extern char *strchr ( __const char *__s, int __c )
__THROW __attribute_pure__ __nonnull ( ( 1 ) );
/* Find the last occurrence of C in S. */
extern char *strrchr ( __const char *__s, int __c )
__THROW __attribute_pure__ __nonnull ( ( 1 ) );
__END_NAMESPACE_STD
173
#ifdef __USE_GNU
/* This function is similar to `strchr'. But it returns a pointer to
176 the closing NUL byte in case C is not found in S. */
extern char *strchrnul ( __const char *__s, int __c )
__THROW __attribute_pure__ __nonnull ( ( 1 ) );
179 #endif
__BEGIN_NAMESPACE_STD
/* Return the length of the initial segment of S which
consists entirely of characters not in REJECT. */
184 extern size_t strcspn ( __const char *__s, __const char *__reject )
__THROW __attribute_pure__ __nonnull ( ( 1, 2 ) );
186 /* Return the length of the initial segment of S which
consists entirely of characters in ACCEPT. */
extern size_t strspn ( __const char *__s, __const char *__accept )
__THROW __attribute_pure__ __nonnull ( ( 1, 2 ) );
/* Find the first occurrence in S of any character in ACCEPT. */
extern char *strpbrk ( __const char *__s, __const char *__accept )
__THROW __attribute_pure__ __nonnull ( ( 1, 2 ) );
/* Find the first occurrence of NEEDLE in HAYSTACK. */
extern char *strstr ( __const char *__haystack, __const char *__needle )
195 __THROW __attribute_pure__ __nonnull ( ( 1, 2 ) );
197
/* Divide S into tokens separated by characters in DELIM. */
extern char *strtok ( char *__restrict __s, __const char *__restrict __delim )
__THROW __nonnull ( ( 2 ) );
__END_NAMESPACE_STD
202
203 /* Divide S into tokens separated by characters in DELIM. Information
passed between calls are stored in SAVE_PTR. */
extern char *__strtok_r ( char *__restrict __s,
__const char *__restrict __delim,
char **__restrict __save_ptr )
__THROW __nonnull ( ( 2, 3 ) );
#if defined __USE_POSIX || defined __USE_MISC
210 extern char *strtok_r ( char *__restrict __s, __const char *__restrict __delim,
char **__restrict __save_ptr )
212 __THROW __nonnull ( ( 2, 3 ) );
#endif
#ifdef __USE_GNU
216 /* Similar to `strstr' but this function ignores the case of both strings. */
extern char *strcasestr ( __const char *__haystack, __const char *__needle )
218 __THROW __attribute_pure__ __nonnull ( ( 1, 2 ) );
219 #endif
221 #ifdef __USE_GNU
/* Find the first occurrence of NEEDLE in HAYSTACK.
NEEDLE is NEEDLELEN bytes long;
HAYSTACK is HAYSTACKLEN bytes long. */
225 extern void *memmem ( __const void *__haystack, size_t __haystacklen,
__const void *__needle, size_t __needlelen )
__THROW __attribute_pure__ __nonnull ( ( 1, 3 ) );
/* Copy N bytes of SRC to DEST, return pointer to bytes after the
last written byte. */
extern void *__mempcpy ( void *__restrict __dest,
__const void *__restrict __src, size_t __n )
__THROW __nonnull ( ( 1, 2 ) );
234 extern void *mempcpy ( void *__restrict __dest,
__const void *__restrict __src, size_t __n )
__THROW __nonnull ( ( 1, 2 ) );
#endif
239
__BEGIN_NAMESPACE_STD
/* Return the length of S. */
242 extern size_t strlen ( __const char *__s )
__THROW __attribute_pure__ __nonnull ( ( 1 ) );
__END_NAMESPACE_STD
#ifdef __USE_GNU
/* Find the length of STRING, but scan at most MAXLEN characters.
If no '\0' terminator is found in that many characters, return MAXLEN. */
extern size_t strnlen ( __const char *__string, size_t __maxlen )
__THROW __attribute_pure__ __nonnull ( ( 1 ) );
#endif
__BEGIN_NAMESPACE_STD
/* Return a string describing the meaning of the `errno' code in ERRNUM. */
extern char *strerror ( int __errnum ) __THROW;
__END_NAMESPACE_STD
#if defined __USE_XOPEN2K || defined __USE_MISC
259 /* Reentrant version of `strerror'.
There are 2 flavors of `strerror_r', GNU which returns the string
and may or may not use the supplied temporary buffer and POSIX one
which fills the string into the buffer.
To use the POSIX version, -D_XOPEN_SOURCE=600 or -D_POSIX_C_SOURCE=200112L
without -D_GNU_SOURCE is needed, otherwise the GNU version is
preferred. */
266 # if defined __USE_XOPEN2K && !defined __USE_GNU
/* Fill BUF with a string describing the meaning of the `errno' code in
ERRNUM. */
# ifdef __REDIRECT_NTH
extern int __REDIRECT_NTH ( strerror_r,
( int __errnum, char *__buf, size_t __buflen ),
__xpg_strerror_r ) __nonnull ( ( 2 ) );
273 # else
extern int __xpg_strerror_r ( int __errnum, char *__buf, size_t __buflen )
__THROW __nonnull ( ( 2 ) );
# define strerror_r __xpg_strerror_r
277 # endif
# else
/* If a temporary buffer is required, at most BUFLEN bytes of BUF will be
used. */
281 extern char *strerror_r ( int __errnum, char *__buf, size_t __buflen )
__THROW __nonnull ( ( 2 ) );
# endif
284 #endif
/* We define this function always since `bzero' is sometimes needed when
the namespace rules does not allow this. */
288 extern void __bzero ( void *__s, size_t __n ) __THROW __nonnull ( ( 1 ) );
#ifdef __USE_BSD
/* Copy N bytes of SRC to DEST ( like memmove, but args reversed ). */
292 extern void bcopy ( __const void *__src, void *__dest, size_t __n )
__THROW __nonnull ( ( 1, 2 ) );
/* Set N bytes of S to 0. */
extern void bzero ( void *__s, size_t __n ) __THROW __nonnull ( ( 1 ) );
297
/* Compare N bytes of S1 and S2 ( same as memcmp ). */
extern int bcmp ( __const void *__s1, __const void *__s2, size_t __n )
__THROW __attribute_pure__ __nonnull ( ( 1, 2 ) );
302 /* Find the first occurrence of C in S ( same as strchr ). */
extern char *index ( __const char *__s, int __c )
304 __THROW __attribute_pure__ __nonnull ( ( 1 ) );
/* Find the last occurrence of C in S ( same as strrchr ). */
extern char *rindex ( __const char *__s, int __c )
__THROW __attribute_pure__ __nonnull ( ( 1 ) );
310 /* Return the position of the first bit set in I, or 0 if none are set.
311 The least-significant bit is position 1, the most-significant 32. */
extern int ffs ( int __i ) __THROW __attribute__ ( ( __const__ ) );
314 /* The following two functions are non-standard but necessary for non-32 bit
315 platforms. */
# ifdef __USE_GNU
extern int ffsl ( long int __l ) __THROW __attribute__ ( ( __const__ ) );
# ifdef __GNUC__
__extension__ extern int ffsll ( long long int __ll )
__THROW __attribute__ ( ( __const__ ) );
321 # endif
# endif
323
/* Compare S1 and S2, ignoring case. */
325 extern int strcasecmp ( __const char *__s1, __const char *__s2 )
__THROW __attribute_pure__ __nonnull ( ( 1, 2 ) );
327
/* Compare no more than N chars of S1 and S2, ignoring case. */
extern int strncasecmp ( __const char *__s1, __const char *__s2, size_t __n )
__THROW __attribute_pure__ __nonnull ( ( 1, 2 ) );
#endif /* Use BSD. */
333 #ifdef __USE_GNU
/* Again versions of a few functions which use the given locale instead
335 of the global one. */
extern int strcasecmp_l ( __const char *__s1, __const char *__s2,
__locale_t __loc )
__THROW __attribute_pure__ __nonnull ( ( 1, 2, 3 ) );
340 extern int strncasecmp_l ( __const char *__s1, __const char *__s2,
341 size_t __n, __locale_t __loc )
__THROW __attribute_pure__ __nonnull ( ( 1, 2, 4 ) );
#endif
344
#ifdef __USE_BSD
/* Return the next DELIM-delimited token from *STRINGP,
347 terminating it with a '\0', and update *STRINGP to point past it. */
extern char *strsep ( char **__restrict __stringp,
349 __const char *__restrict __delim )
__THROW __nonnull ( ( 1, 2 ) );
#endif
#ifdef __USE_GNU
354 /* Compare S1 and S2 as strings holding name & indices/version numbers. */
extern int strverscmp ( __const char *__s1, __const char *__s2 )
__THROW __attribute_pure__ __nonnull ( ( 1, 2 ) );
357
/* Return a string describing the meaning of the signal number in SIG. */
extern char *strsignal ( int __sig ) __THROW;
/* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */
362 extern char *__stpcpy ( char *__restrict __dest, __const char *__restrict __src )
__THROW __nonnull ( ( 1, 2 ) );
extern char *stpcpy ( char *__restrict __dest, __const char *__restrict __src )
365 __THROW __nonnull ( ( 1, 2 ) );
/* Copy no more than N characters of SRC to DEST, returning the address of
the last character written into DEST. */
extern char *__stpncpy ( char *__restrict __dest,
__const char *__restrict __src, size_t __n )
__THROW __nonnull ( ( 1, 2 ) );
372 extern char *stpncpy ( char *__restrict __dest,
__const char *__restrict __src, size_t __n )
__THROW __nonnull ( ( 1, 2 ) );
/* Sautee STRING briskly. */
extern char *strfry ( char *__string ) __THROW __nonnull ( ( 1 ) );
/* Frobnicate N bytes of S. */
extern void *memfrob ( void *__s, size_t __n ) __THROW __nonnull ( ( 1 ) );
# ifndef basename
/* Return the file name within directory of FILENAME. We don't
declare the function if the `basename' macro is available ( defined
in <libgen.h> ) which makes the XPG version of this function
available. */
extern char *basename ( __const char *__filename ) __THROW __nonnull ( ( 1 ) );
# endif
#endif
#if defined __GNUC__ && __GNUC__ >= 2
# if defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__ \
&& !defined __NO_INLINE__ && !defined __cplusplus
/* When using GNU CC we provide some optimized versions of selected
functions from this header. There are two kinds of optimizations:
- machine-dependent optimizations, most probably using inline
assembler code; these might be quite expensive since the code
size can increase significantly.
These optimizations are not used unless the symbol
__USE_STRING_INLINES
is defined before including this header.
- machine-independent optimizations which do not increase the
code size significantly and which optimize mainly situations
where one or more arguments are compile-time constants.
These optimizations are used always when the compiler is
taught to optimize.
410
One can inhibit all optimizations by defining __NO_STRING_INLINES. */
/* Get the machine-dependent optimizations ( if any ). */
# include <bits/string.h>
/* These are generic optimizations which do not add too much inline code. */
# include <bits/string2.h>
# endif
# if __USE_FORTIFY_LEVEL > 0 && !defined __cplusplus
/* Functions with security checks. */
# include <bits/string3.h>
# endif
#endif
__END_DECLS
#endif /* string.h */
1 /*
* Host code generation
*
* Copyright ( c ) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or ( at your option ) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdarg.h>
#include <stdlib.h>
#include "stdio.h"
#include "string.h"
#include <inttypes.h>
#include "config.h"
#define NO_CPU_IO_DEFS
#include "cpu.h"
#include "exec-all.h"
#include "disas.h"
typedef int ( *cpu_gen_code_func )( CPUState* env,
TranslationBlock* tb,
int max_code_size,
int* gen_code_size_ptr );
typedef int ( *cpu_restore_state_func )( TranslationBlock* tb,
CPUState* env,
unsigned long searched_pc,
void* puc );
typedef void ( *dump_ops_func )( const uint16_t *opc_buf, const uint32_t *opparam_buf );
extern cpu_gen_code_func _cpu_gen_code;
extern cpu_restore_state_func _cpu_restore_state;
extern dump_ops_func _dump_ops;
#ifdef GEN_TRACE
#define OPC_H "opc-trace.h"
#define CPU_GEN_CODE trace_cpu_gen_code
#define CPU_RESTORE_STATE trace_cpu_restore_state
#define DUMP_OPS trace_dump_ops
#else
#define OPC_H "opc.h"
#define CPU_GEN_CODE default_cpu_gen_code
#define CPU_RESTORE_STATE default_cpu_restore_state
#define DUMP_OPS default_dump_ops
#endif
65 extern int dyngen_code( uint8_t *gen_code_buf,
uint16_t *label_offsets, uint16_t *jmp_offsets,
const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels );
enum {
#define DEF( s, n, copy_size ) INDEX_op_ ## s,
#include OPC_H
#undef DEF
NB_OPS,
};
uint16_t gen_opc_buf[OPC_BUF_SIZE];
uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
long gen_labels[OPC_BUF_SIZE];
int nb_gen_labels;
target_ulong gen_opc_pc[OPC_BUF_SIZE];
uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
#if defined( TARGET_I386 )
uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
#elif defined( TARGET_SPARC )
target_ulong gen_opc_npc[OPC_BUF_SIZE];
target_ulong gen_opc_jump_pc[2];
#elif defined( TARGET_MIPS )
uint32_t gen_opc_hflags[OPC_BUF_SIZE];
#endif
#ifndef GEN_TRACE
int code_copy_enabled = 1;
#endif
#ifdef DEBUG_DISAS
static const char *op_str[] = {
#define DEF( s, n, copy_size ) #s,
#include OPC_H
#undef DEF
};
static uint8_t op_nb_args[] = {
#define DEF( s, n, copy_size ) n,
#include OPC_H
#undef DEF
};
static const unsigned short opc_copy_size[] = {
#define DEF( s, n, copy_size ) copy_size,
#include OPC_H
#undef DEF
};
115 void DUMP_OPS( const uint16_t *opc_buf, const uint32_t *opparam_buf )
{
const uint16_t *opc_ptr;
const uint32_t *opparam_ptr;
int c, n, i;
opc_ptr = opc_buf;
opparam_ptr = opparam_buf;
for( ;; ) {
c = *opc_ptr++;
n = op_nb_args[c];
fprintf( logfile, "0x%04x: %s",
( int )( opc_ptr - opc_buf - 1 ), op_str[c] );
for( i = 0; i < n; i++ ) {
fprintf( logfile, " 0x%x", opparam_ptr[i] );
}
fprintf( logfile, "\n" );
if ( c == INDEX_op_end )
break;
opparam_ptr += n;
}
}
#endif
/* compute label info */
141 static void dyngen_labels( long *gen_labels, int nb_gen_labels,
uint8_t *gen_code_buf, const uint16_t *opc_buf )
{
uint8_t *gen_code_ptr;
int c, i;
unsigned long gen_code_addr[OPC_BUF_SIZE];
if ( nb_gen_labels == 0 )
return;
/* compute the address of each op code */
gen_code_ptr = gen_code_buf;
i = 0;
for( ;; ) {
c = opc_buf[i];
gen_code_addr[i] =( unsigned long )gen_code_ptr;
if ( c == INDEX_op_end )
break;
gen_code_ptr += opc_copy_size[c];
i++;
}
/* compute the address of each label */
for( i = 0; i < nb_gen_labels; i++ ) {
gen_labels[i] = gen_code_addr[gen_labels[i]];
}
}
/* return non zero if the very first instruction is invalid so that
the virtual CPU can trigger an exception.
'*gen_code_size_ptr' contains the size of the generated code ( host
code ).
*/
175 static int CPU_GEN_CODE( CPUState *env, TranslationBlock *tb,
int max_code_size, int *gen_code_size_ptr )
{
uint8_t *gen_code_buf;
int gen_code_size;
#ifdef USE_CODE_COPY
if ( code_copy_enabled &&
cpu_gen_code_copy( env, tb, max_code_size, &gen_code_size ) == 0 ) {
/* nothing more to do */
} else
#endif
{
if ( gen_intermediate_code( env, tb ) < 0 )
return -1;
/* generate machine code */
tb->tb_next_offset[0] = 0xffff;
tb->tb_next_offset[1] = 0xffff;
gen_code_buf = tb->tc_ptr;
#ifdef USE_DIRECT_JUMP
/* the following two entries are optional ( only used for string ops ) */
tb->tb_jmp_offset[2] = 0xffff;
tb->tb_jmp_offset[3] = 0xffff;
#endif
dyngen_labels( gen_labels, nb_gen_labels, gen_code_buf, gen_opc_buf );
gen_code_size = dyngen_code( gen_code_buf, tb->tb_next_offset,
#ifdef USE_DIRECT_JUMP
tb->tb_jmp_offset,
#else
NULL,
#endif
gen_opc_buf, gen_opparam_buf, gen_labels );
}
*gen_code_size_ptr = gen_code_size;
#ifdef DEBUG_DISAS
if ( loglevel & CPU_LOG_TB_OUT_ASM ) {
fprintf( logfile, "OUT: [size=%d]\n", *gen_code_size_ptr );
disas( logfile, tb->tc_ptr, *gen_code_size_ptr );
fprintf( logfile, "\n" );
fflush( logfile );
}
#endif
return 0;
}
/* The cpu state corresponding to 'searched_pc' is restored.
*/
224 static int CPU_RESTORE_STATE( TranslationBlock *tb,
CPUState *env, unsigned long searched_pc,
void *puc )
{
int j, c;
unsigned long tc_ptr;
uint16_t *opc_ptr;
#ifdef USE_CODE_COPY
if ( tb->cflags & CF_CODE_COPY ) {
return cpu_restore_state_copy( tb, env, searched_pc, puc );
}
#endif
if ( gen_intermediate_code_pc( env, tb ) < 0 )
return -1;
/* find opc index corresponding to search_pc */
tc_ptr = ( unsigned long )tb->tc_ptr;
if ( searched_pc < tc_ptr )
return -1;
j = 0;
opc_ptr = gen_opc_buf;
for( ;; ) {
c = *opc_ptr;
if ( c == INDEX_op_end )
return -1;
tc_ptr += opc_copy_size[c];
if ( searched_pc < tc_ptr )
break;
opc_ptr++;
}
j = opc_ptr - gen_opc_buf;
/* now find start of instruction before */
while ( gen_opc_instr_start[j] == 0 )
j--;
#if defined( TARGET_I386 )
{
int cc_op;
#ifdef DEBUG_DISAS
if ( loglevel & CPU_LOG_TB_OP ) {
int i;
fprintf( logfile, "RESTORE:\n" );
for( i=0;i<=j; i++ ) {
if ( gen_opc_instr_start[i] ) {
fprintf( logfile, "0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i] );
}
}
fprintf( logfile, "spc=0x%08lx j=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n",
searched_pc, j, gen_opc_pc[j] - tb->cs_base,
( uint32_t )tb->cs_base );
}
#endif
env->eip = gen_opc_pc[j] - tb->cs_base;
cc_op = gen_opc_cc_op[j];
if ( cc_op != CC_OP_DYNAMIC )
env->cc_op = cc_op;
}
#elif defined( TARGET_ARM )
env->regs[15] = gen_opc_pc[j];
#elif defined( TARGET_SPARC )
{
target_ulong npc;
env->pc = gen_opc_pc[j];
npc = gen_opc_npc[j];
if ( npc == 1 ) {
/* dynamic NPC: already stored */
} else if ( npc == 2 ) {
target_ulong t2 = ( target_ulong )puc;
/* jump PC: use T2 and the jump targets of the translation */
if ( t2 )
env->npc = gen_opc_jump_pc[0];
else
env->npc = gen_opc_jump_pc[1];
} else {
env->npc = npc;
}
}
#elif defined( TARGET_PPC )
{
int type;
/* for PPC, we need to look at the micro operation to get the
access type */
env->nip = gen_opc_pc[j];
switch( c ) {
#if defined( CONFIG_USER_ONLY )
#define CASE3( op )\
case INDEX_op_ ## op ## _raw
#else
#define CASE3( op )\
case INDEX_op_ ## op ## _user:\
case INDEX_op_ ## op ## _kernel
#endif
CASE3( stfd ):
CASE3( stfs ):
CASE3( lfd ):
CASE3( lfs ):
type = ACCESS_FLOAT;
break;
CASE3( lwarx ):
type = ACCESS_RES;
break;
CASE3( stwcx ):
type = ACCESS_RES;
break;
CASE3( eciwx ):
CASE3( ecowx ):
type = ACCESS_EXT;
break;
default:
type = ACCESS_INT;
break;
}
env->access_type = type;
}
#elif defined( TARGET_MIPS )
env->PC = gen_opc_pc[j];
env->hflags &= ~MIPS_HFLAG_BMASK;
env->hflags |= gen_opc_hflags[j];
#endif
return 0;
}
347
#ifdef GEN_TRACE
void qemu_trace_enable_gencode( void )
{
_cpu_gen_code = CPU_GEN_CODE;
_cpu_restore_state = CPU_RESTORE_STATE;
_dump_ops = DUMP_OPS;
}
#else
cpu_gen_code_func _cpu_gen_code = CPU_GEN_CODE;
360 cpu_restore_state_func _cpu_restore_state = CPU_RESTORE_STATE;
dump_ops_func _dump_ops = DUMP_OPS;
void qemu_trace_disable_gencode( void )
{
_cpu_gen_code = CPU_GEN_CODE;
_cpu_restore_state = CPU_RESTORE_STATE;
367 _dump_ops = DUMP_OPS;
}
int cpu_gen_code( CPUState *env, TranslationBlock *tb,
int max_code_size, int *gen_code_size_ptr )
{
373 return ( *_cpu_gen_code )( env, tb, max_code_size, gen_code_size_ptr );
}
int cpu_restore_state( TranslationBlock *tb,
CPUState *env, unsigned long searched_pc,
void *puc )
{
380 return ( *_cpu_restore_state )( tb, env, searched_pc, puc );
}
void dump_ops( const uint16_t *opc_buf, const uint32_t *opparam_buf )
{
( *_dump_ops )( opc_buf, opparam_buf );
}
#endif
/*
* linux/arch/arm/kernel/traps.c
*
* Copyright ( C ) 1995-2002 Russell King
* Fragments that appear the same as linux/arch/i386/kernel/traps.c ( C ) Linus Torvalds
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 'traps.c' handles hardware exceptions after we have saved some state in
* 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably
* kill the offending process.
*/
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/spinlock.h>
#include <linux/personality.h>
#include <linux/kallsyms.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <asm/atomic.h>
#include <asm/cacheflush.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/traps.h>
#include <asm/io.h>
#include "stdio.h"
static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
#ifdef CONFIG_DEBUG_USER
unsigned int user_debug;
static int __init user_debug_setup( char *str )
{
40 get_option( &str, &user_debug );
return 1;
}
__setup( "user_debug=", user_debug_setup );
#endif
static void dump_mem( const char *str, unsigned long bottom, unsigned long top );
/*
* Dump out the contents of some memory nicely...
*/
static void dump_mem( const char *str, unsigned long bottom, unsigned long top )
{
unsigned long p = bottom & ~31;
mm_segment_t fs;
int i;
/*
* We need to switch to kernel mode so that we can use __get_user
* to safely read from kernel space. Note that we now dump the
* code first, just in case the backtrace kills us.
*/
fs = get_fs( );
set_fs( KERNEL_DS );
printf( "%s( 0x%08lx to 0x%08lx )\n", str, bottom, top );
for ( p = bottom & ~31; p < top; ) {
printf( "%04lx: ", p & 0xffff );
for ( i = 0; i < 8; i++, p += 4 ) {
unsigned int val;
if ( p < bottom || p >= top )
printf( " " );
else {
__get_user( val, ( unsigned long * )p );
printf( "%08x ", val );
}
}
printf ( "\n" );
}
set_fs( fs );
}
void dump_stack( void )
{
// __backtrace( );
}
EXPORT_SYMBOL( dump_stack );
void show_stack( struct task_struct *tsk, unsigned long *sp )
{
unsigned long fp;
if ( !tsk )
tsk = current;
if ( tsk != current )
fp = thread_saved_fp( tsk );
else
asm( "mov %0, fp" : "=r" ( fp ) : : "cc" );
// VMM c_backtrace( fp, 0x10 );
barrier( );
}
#ifdef CONFIG_PREEMPT
#define S_PREEMPT " PREEMPT"
#else
#define S_PREEMPT ""
#endif
#ifdef CONFIG_SMP
#define S_SMP " SMP"
#else
#define S_SMP ""
#endif
static LIST_HEAD( undef_hook );
static DEFINE_SPINLOCK( undef_lock );
void register_undef_hook( struct undef_hook *hook )
{
unsigned long flags;
spin_lock_irqsave( &undef_lock, flags );
list_add( &hook->node, &undef_hook );
spin_unlock_irqrestore( &undef_lock, flags );
}
void unregister_undef_hook( struct undef_hook *hook )
{
unsigned long flags;
spin_lock_irqsave( &undef_lock, flags );
list_del( &hook->node );
spin_unlock_irqrestore( &undef_lock, flags );
}
asmlinkage void __exception do_undefinstr( struct pt_regs *regs )
{
unsigned int correction = thumb_mode( regs ) ? 2 : 4;
unsigned int instr;
struct undef_hook *hook;
siginfo_t info;
void __user *pc;
unsigned long flags;
/*
* According to the ARM ARM, PC is 2 or 4 bytes ahead,
* depending whether we're in Thumb mode or not.
* Correct this offset.
*/
regs->ARM_pc -= correction;
pc = ( void __user * )instruction_pointer( regs );
if ( processor_mode( regs ) == SVC_MODE ) {
instr = *( u32 * ) pc;
}
#ifdef VMM
else if ( thumb_mode( regs ) ) {
get_user( instr, ( u16 __user * )pc );
} else {
get_user( instr, ( u32 __user * )pc );
}
#endif
spin_lock_irqsave( &undef_lock, flags );
list_for_each_entry( hook, &undef_hook, node ) {
if ( ( instr & hook->instr_mask ) == hook->instr_val &&
( regs->ARM_cpsr & hook->cpsr_mask ) == hook->cpsr_val ) {
if ( hook->fn( regs, instr ) == 0 ) {
spin_unlock_irq( &undef_lock );
return;
}
}
}
spin_unlock_irqrestore( &undef_lock, flags );
#ifdef CONFIG_DEBUG_USER
if ( user_debug & UDBG_UNDEFINED ) {
printf( KERN_INFO "%s ( %d ): undefined instruction: pc=%p\n",
current->comm, current->pid, pc );
dump_instr( regs );
}
#endif
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_ILLOPC;
info.si_addr = pc;
//VMM arm_notify_die( "Oops - undefined instruction", regs, &info, 0, 6 );
}
asmlinkage void do_unexp_fiq ( struct pt_regs *regs )
{
printf( "Hmm. Unexpected FIQ received, but trying to continue\n" );
printf( "You may have a hardware problem...\n" );
}
/*
* bad_mode handles the impossible case in the vectors. If you see one of
* these, then it's extremely serious, and could mean you have buggy hardware.
* It never returns, and never tries to sync. We hope that we can at least
* dump out some state information...
*/
asmlinkage void bad_mode( struct pt_regs *regs, int reason )
{
//VMM console_verbose( );
printf( "Bad mode in %s handler detected\n", handler[reason] );
// VMM die( "Oops - bad mode", regs, 0 );
local_irq_disable( );
// VMM panic( "bad mode" );
}
static inline void
do_cache_op( unsigned long start, unsigned long end, int flags )
{
struct vm_area_struct *vma;
if ( end < start || flags )
return;
vma = find_vma( current->active_mm, start );
if ( vma && vma->vm_start < end ) {
if ( start < vma->vm_start )
start = vma->vm_start;
if ( end > vma->vm_end )
end = vma->vm_end;
flush_cache_user_range( vma, start, end );
}
}
#ifdef CONFIG_TLS_REG_EMUL
/*
* We might be running on an ARMv6+ processor which should have the TLS
* register but for some reason we can't use it, or maybe an SMP system
* using a pre-ARMv6 processor ( there are apparently a few prototypes like
* that in existence ) and therefore access to that register must be
* emulated.
*/
static int get_tp_trap( struct pt_regs *regs, unsigned int instr )
{
int reg = ( instr >> 12 ) & 15;
if ( reg == 15 )
return 1;
regs->uregs[reg] = current_thread_info( )->tp_value;
regs->ARM_pc += 4;
return 0;
}
static struct undef_hook arm_mrc_hook = {
.instr_mask = 0x0fff0fff,
.instr_val = 0x0e1d0f70,
.cpsr_mask = PSR_T_BIT,
.cpsr_val = 0,
.fn = get_tp_trap,
};
static int __init arm_mrc_hook_init( void )
{
register_undef_hook( &arm_mrc_hook );
return 0;
}
late_initcall( arm_mrc_hook_init );
#endif
void __bad_xchg( volatile void *ptr, int size )
{
printf( "xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n",
__builtin_return_address( 0 ), ptr, size );
BUG( );
}
EXPORT_SYMBOL( __bad_xchg );
/*
* A data abort trap was taken, but we did not handle the instruction.
* Try to abort the user program, or panic if it was the kernel.
*/
asmlinkage void
baddataabort( int code, unsigned long instr, struct pt_regs *regs )
{
unsigned long addr = instruction_pointer( regs );
siginfo_t info;
#ifdef CONFIG_DEBUG_USER
if ( user_debug & UDBG_BADABORT ) {
printf( KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n",
current->pid, current->comm, code, instr );
dump_instr( regs );
show_pte( current->mm, addr );
}
#endif
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_ILLOPC;
info.si_addr = ( void __user * )addr;
// VMM arm_notify_die( "unknown data abort code", regs, &info, instr, 0 );
}
void __attribute__( ( noreturn ) ) __bug( const char *file, int line )
{
printf( KERN_CRIT"kernel BUG at %s:%d!\n", file, line );
*( int * )0 = 0;
/* Avoid "noreturn function does return" */
for ( ;; );
}
EXPORT_SYMBOL( __bug );
void __readwrite_bug( const char *fn )
{
printf( "%s called, but not implemented\n", fn );
BUG( );
}
EXPORT_SYMBOL( __readwrite_bug );
void __pte_error( const char *file, int line, unsigned long val )
{
printf( "%s:%d: bad pte %08lx.\n", file, line, val );
}
void __pmd_error( const char *file, int line, unsigned long val )
{
printf( "%s:%d: bad pmd %08lx.\n", file, line, val );
}
void __pgd_error( const char *file, int line, unsigned long val )
{
printf( "%s:%d: bad pgd %08lx.\n", file, line, val );
}
asmlinkage void __div0( void )
{
printf( "Division by zero in kernel.\n" );
dump_stack( );
}
EXPORT_SYMBOL( __div0 );
void abort( void )
{
BUG( );
/* if that doesn't kill us, halt */
panic( "Oops failed to kill thread" );
}
EXPORT_SYMBOL( abort );
void __init trap_init( void )
{
unsigned long vectors = CONFIG_VECTORS_BASE;
extern char __stubs_start[], __stubs_end[];
extern char __vectors_start[], __vectors_end[];
extern char __kuser_helper_start[], __kuser_helper_end[];
int kuser_sz = __kuser_helper_end - __kuser_helper_start;
/*
* Copy the vectors, stubs and kuser helpers ( in entry-armv.S )
* into the vector page, mapped at 0xffff0000, and ensure these
* are visible to the instruction stream.
*/
memcpy( ( void * )vectors, __vectors_start, __vectors_end - __vectors_start );
memcpy( ( void * )vectors + 0x200, __stubs_start, __stubs_end - __stubs_start );
memcpy( ( void * )vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz );
/*
* Copy signal return handlers into the vector page, and
* set sigreturn to be a pointer to these.
*/
// memcpy( ( void * )KERN_SIGRETURN_CODE, sigreturn_codes,
// sizeof( sigreturn_codes ) );
// flush_icache_range( vectors, vectors + PAGE_SIZE );
modify_domain( DOMAIN_USER, DOMAIN_CLIENT );
}
1
typedef struct cp15regs {
volatile unsigned int transbase;
volatile unsigned int ctrl;
volatile unsigned int dac;
} CP15Regs;
typedef struct CPUARMState {
/* Regs for current mode. */
uint32_t regs[16];
} CPUARMState;
typedef struct VMState {
int ram_size;
const char *kernel_location;
const char *kernel_cmdline;
const char *initrd_location;
uint32_t kernel_size;
uint32_t ramdisk_size;
uint32_t loader_start;
} VMState;