You are on page 1of 12

BBED> info

File# Name Size(blks)


----- ---- ----------
1 /u01/app/oracle/oradata/test1212/system01.dbf 87040
2 /u01/app/oracle/oradata/test1212/sysaux01.dbf 64000
3 /u01/app/oracle/oradata/test1212/undotbs01.dbf 45440
4 /u01/app/oracle/oradata/test1212/users01.dbf 16640
5 /u01/app/oracle/oradata/test1212/ss01.dbf 12800

BBED> show all


FILE# 1
BLOCK# 1
OFFSET 0 --偏移量,0 代表从第 1 个字节,
DBA 0x00400001 (4194305 1,1) --DBA(data block addr)的组成 = 文件号 + 块号,
一共 32 位
FILENAME /u01/app/oracle/oradata/test1212/system01.dbf
BIFILE bifile.bbd
LISTFILE dbfiles.txt
BLOCKSIZE 8192
MODE Edit
EDIT Unrecoverable
IBASE Dec
OBASE Dec
WIDTH 80
COUNT 512
LOGFILE log.bbd
SPOOL No

备注:

DBA(data block addr) = file#(10bit) + block#(22bit) =32bit


所以文件个数最多是 2 的 10 次方=1024 个

DBA = 0x00400001 ====> 0000 0000 0100 0000 0000 0000 0000 0001
从以上所知的前 10 位为 file#,所以可以放一个分隔符再看:
0000 0000 01[分隔符]00 0000 0000 0000 0000 0001 (4194305 1,1)
可以看出 file#=1,block#=1 ,就和上面的 show 出来的信息对应起来了

set 命令 --设置相应的信息
如果要查看 2 号文件的 2 号块,则可以使用 set 命令来设置文件号和块号
BBED> set file 2
FILE# 2
BBED> set block 2
BLOCK# 2

BBED> show all


FILE# 2
BLOCK# 2
OFFSET 0
DBA 0x00800002 (8388610 2,2)
FILENAME /u01/app/oracle/oradata/test1212/sysaux01.dbf
BIFILE bifile.bbd
LISTFILE dbfiles.txt
BLOCKSIZE 8192
MODE Edit
EDIT Unrecoverable
IBASE Dec
OBASE Dec
WIDTH 80
COUNT 512
LOGFILE log.bbd
SPOOL No

DBA = 0x00800002 ===》 0000 0000 1000 0000 0000 0000 0000 0010

再次回到 1 号文件的 0 号块
BBED> set file 1
FILE# 1

BBED> set block 0


BLOCK# 0

BBED> show all


FILE# 1
BLOCK# 0
OFFSET 0
DBA 0x00400000 (4194304 1,0)
FILENAME /u01/app/oracle/oradata/test1212/system01.dbf
BIFILE bifile.bbd
LISTFILE dbfiles.txt
BLOCKSIZE 8192
MODE Edit
EDIT Unrecoverable
IBASE Dec
OBASE Dec
WIDTH 80
COUNT 512
LOGFILE log.bbd
SPOOL No

dump 命令 --十六进制查看 block


dump /v --查看十六进制内容的同时以文本方式“翻译”十六进制显示的内容,相当于对当
前 block 执行 strings 命令
BBED> dump
File: /u01/app/oracle/oradata/test1212/system01.dbf (1)
Block: 0 Offsets: 0 to 511 Dba:0x00400000
------------------------------------------------------------------------
00a20000 0000c0ff 00000000 00000000 67ae0000 00200000 00540100 7d7c7b7a
a0810000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
<32 bytes per line>

备注:
从 Offsets 可以看出,只显示了 0-511 个字节的偏移,也就是 512 个字节的信息,因为默认
是 COUNT=512。我们知道 oracle 一个块默认大小 8192,所以如果要让一个块的 dump 信息
显示完全的话,就可以 set count 8192,再执行 dump

map 命令会通过偏移量来显示 block 的详细信息,如 data/block header 和 row directory。


在不指定 block 的情况下,会显示当前 block 的信息,如果想显示其他 block 的信息,可以
使用 file name,file id,block 和 DBA 来指定要显示的 block。
File: /u01/app/oracle/oradata/oracle01/test101.dbf (7)
Block: 132 Dba:0x01c00084
------------------------------------------------------------
KTB Data Block (Table/Cluster)
struct kcbh, 20 bytes @0 --块头信息,cache layer
struct ktbbh, 72 bytes @20 --事务信息,transaction layer
struct kdbh, 14 bytes @100 --对应数据头,占用 14 字节
struct kdbt[1], 4 bytes @114 --表目录*kdbt[0]指针显示值
sb2 kdbr[4] @118 --行目录 *kdbr[0]指针值显示状态 flg
ub1 freespace[8016] @126 --空闲空间
ub1 rowdata[46] @8142 --行数据
ub4 tailchk @8188 --tail check

这个是文件 7,块 132 的,整个块的数据结构。可以看到行数据时从下开始增加的,空闲的


空间是在中间。后面@开头的表示在该块的偏移,@0 表示从该块首开始,@20 表示从第 20
个字节开始。那么 0~19 个字节就是 block-header 的信息了。
tailchk 尾部校验,一共是 8192 个块,因为是从 0 开始的,所以最后一个字节是 8191,换句
话说就是从 8188-8191 这 4 个字节是不能用的,是拿来做尾部校验的

这里可以看到数据是从 8142 开始我们 dump 下这个数据看


BBED> dump /v dba 7,132 offset 8142 count 64
File: /u01/app/oracle/oradata/oracle01/test101.dbf (7)
Block: 132 Offsets: 8142 to 8191 Dba:0x01c00084
-------------------------------------------------------
2c010202 c1020371 77652c00 0202c104 l ,...󿿮.qwe,...󿿮
05454545 45452c00 0202c103 05424242 l .EEEEE,...󿿮.BBB
42422c00 0202c102 05414141 41410106 l BB,...󿿮.AAAAA..
652c l e,
<16 bytes per line>

这些数据的话也能通过 find 查询到


BBED> find /c AAAAA
File: /u01/app/oracle/oradata/oracle01/test101.dbf (7)
Block: 132 Offsets: 8183 to 8191 Dba:0x01c00084
------------------------------------------------------------------------
41414141 41010665 2c
<32 bytes per line>

从 8183 开始显示这个字段信息
我们就 dump 这一点:
BBED> dump /v dba 7,132 offset 8183
File: /u01/app/oracle/oradata/oracle01/test101.dbf (7)
Block: 132 Offsets: 8183 to 8191 Dba:0x01c00084
-------------------------------------------------------
41414141 41010665 2c l AAAAA..e,
<16 bytes per line>
这个就是数据字段了

更改数据字段
BBED> modify /c ABCED dba 7,132 offset 8183
File: /u01/app/oracle/oradata/oracle01/test101.dbf (7)
Block: 132 Offsets: 8183 to 8191 Dba:0x01c00084
------------------------------------------------------------------------
41424345 44010665 2c
<32 bytes per line>

保存数据
BBED> sum dba 7,132 apply
Check value for File 7, Block 132:
current = 0xc875, required = 0xc875

struct kcvf 其实在 oracle 中也有一个视图可以查询 select * from x$kcvfh;


map /v --比 map 更详细的查看 block 里面的信息
BBED> map /v
File: /u01/app/oracle/oradata/test1212/system01.dbf (1)
Block: 1 Dba:0x00400001
------------------------------------------------------------
Data File Header
struct kcvfh, 860 bytes @0
struct kcvfhbfh, 20 bytes @0
struct kcvfhhdr, 76 bytes @20
ub4 kcvfhrdb @96
struct kcvfhcrs, 8 bytes @100
ub4 kcvfhcrt @108
ub4 kcvfhrlc @112

struct kcvfhprfs, 8 bytes @428


ub4 kcvfhtrt @444
ub4 tailchk @8188

print 命令 --查看命令,可以用 p 来简写


如果想对上面的 struct kcvfhbfh 再进行详细的查看,可以使用命令 print 来查看
BBED> p kcvfhbfh
struct kcvfhbfh, 20 bytes @0
ub1 type_kcbh @0 0x0b
ub1 frmt_kcbh @1 0xa2
ub1 spare1_kcbh @2 0x00
ub1 spare2_kcbh @3 0x00
ub4 rdba_kcbh @4 0x00400001
ub4 bas_kcbh @8 0x00000000
ub2 wrp_kcbh @12 0x0000
ub1 seq_kcbh @14 0x01
ub1 flg_kcbh @15 0x04 (KCBHFCKV)
ub2 chkval_kcbh @16 0xe81a
ub2 spare3_kcbh @18 0x0000

1.得到文件的块大小和数据块个数
在 Linux 和 Unix 上,oracle 提供了一个小工具 dbfsize 用于查看文件块大小
(参看[ID:360032.1]How to detect and fix a corruption in the datafile OS header - ORA-27047)

[oracle@ora11g test1212]$ which dbfsize


/u01/app/oracle/product/11.2.0/db_1/bin/dbfsize
--查看控制文件块大小
[oracle@ora11g test1212]$ dbfsize control01.ctl
Database file: control01.ctl
Database file type: file system
Database file size: 594 16384 byte blocks

--查看 redo log 文件块大小


[oracle@ora11g test1212]$ dbfsize redo01.log
Database file: redo01.log
Database file type: file system
Database file size: 102400 512 byte blocks

--查看 system01 文件块大小


[oracle@ora11g test1212]$ dbfsize system01.dbf
Database file: system01.dbf
Database file type: file system
Database file size: 87040 8192 byte blocks

可以看到通过 dbfsize 可以得到 system01.dbf 这个文件的块信息有 2 个数据: 87040 和


8192。

现在我们要通过 bbed 来做查询得到相应的信息


首先我们用 bbed 定位到 1 号文件的 0 号块,并 dump 出相应的信息来
BBED> set file 1
FILE# 1

BBED> set block 0


BLOCK# 0

BBED> show all


FILE# 1
BLOCK# 0
OFFSET 0
DBA 0x00400000 (4194304 1,0)
FILENAME /u01/app/oracle/oradata/test1212/system01.dbf
BIFILE bifile.bbd
LISTFILE dbfiles.txt
BLOCKSIZE 8192
MODE Edit
EDIT Unrecoverable
IBASE Dec
OBASE Dec
WIDTH 80
COUNT 512
LOGFILE log.bbd
SPOOL No

BBED> dump
File: /u01/app/oracle/oradata/test1212/system01.dbf (1)
Block: 0 Offsets: 0 to 511 Dba:0x00400000
-----------------------------------------------------------------------
00a20000 0000c0ff 00000000 00000000 67ae0000 00200000 00540100 7d7c7b7a
a0810000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

以上就是 1 号文件 0 号块 dump 出来的信息。经查询资料,我们先有一个通过实验总结出来


的结论:
第 20-23 个字节,存放了数据块的大小;第 24-27 个字节,存放了数据文件的大小。
对 比 上 面 的 信 息 可 以 得 到 : 第 20-23 个 字 节 是 “ 00200000” , 第 24-27 个 字 节 是
“00540100”
那么我们怎么得到“00200000”和“00540100”这 2 个对应的十进制数是多少呢?

在这里,我们先要了解操作系统的一个有关 cpu 的知识----字节顺序。


在几乎所有的机器上,多字节对象都被存储为连续的字节序列,对象的地址为所有使用字
节中最小的地址。
假设一个类型为 int 的变量 x 的地址为 0x100,也就是说,地址表达式&x 的值 为 0x100。
那么 x 的 4 个字节将被存储在存储器的 0x100、0x101 、0x102、 x103 位置。
某些机器选择在存储器中按照从最低有效字节到高位有效字节的顺序存储对象,而另一些
机器则按照从最高有效字节到最低有效字节的顺序存储。
前一种规则:最低有效字节在最前面的方式,称为小端法(little endian)。 后一种规则:最高
有效字节在最前面的方式,称为大端法(big endian)。

Oracle 给我们提供了一个字典表来查询系统是大端还是小端:
SQL> select * from V$TRANSPORTABLE_PLATFORM ORDER BY PLATFORM_ID;
PLATFORM_ID PLATFORM_NAME ENDIAN_FORMAT
----------- -------------------------------------------------- ----------------------------
1 Solaris[tm] OE (32-bit) Big
2 Solaris[tm] OE (64-bit) Big
3 HP-UX (64-bit) Big
4 HP-UX IA (64-bit) Big
5 HP Tru64 UNIX Little
6 AIX-Based Systems (64-bit) Big
7 Microsoft Windows IA (32-bit) Little
8 Microsoft Windows IA (64-bit) Little
9 IBM zSeries Based Linux Big
10 Linux IA (32-bit) Little
11 Linux IA (64-bit) Little
12 Microsoft Windows x86 64-bit Little
13 Linux x86 64-bit Little
15 HP Open VMS Little
16 Apple Mac OS Big
17 Solaris Operating System (x86) Little
18 IBM Power Based Linux Big
19 HP IA Open VMS Little
20 Solaris Operating System (x86-64) Little
21 Apple Mac OS (x86-64) Little

有了上面的补充知识,那么回过来看“00200000”和“00540100”。因为我机器的环境是
linux 64 位,所以是小端,所以在存储的时候其实是取反了再存的。

我们把“00200000”和“00540100” 取反,再转换成 10 进制:


因为 16 进制是 2 位一个字节,所以以每两位为单位进行取反:(如 12345678 取反==》7856
3412)
00200000 取反==》0000 0020
select to_number('2000','xxxxxx') from dual; 8192

00540100 取反==》00015400
select to_number('15400','xxxxxx') from dual; 87040

如上所示,得到了“00200000”和“00540100”的 10 进制结果分别是 8192 和 87040,就和


之前的 dbfsize 所得到的结果一致了。

备注:

元数据中:number 类型都要进行反,而字符类型不需要取反;而数据库的表里面的 number


类型也不需要取反

2.查看 dbid 和 sid


通过 sql 语句查询,我们可以查询到 sid 和 dbid 的信息
SQL> select dbid,name from v$database;
DBID NAME
---------- ---------------
3488422402 TEST1212
那么怎么通过 bbed 去验证它呢?

首先,要有一个通过实验总结出来的:每个文件头的 1 号块都有 dbid 和 sid,dbid 的信息存


放在块的第 28-31 个字节,而 sid 的信息存放在第 32-39 个字节中
我们在这儿取 1 号文件的 1 号块,并 dump 出来:
BBED> set file 1
FILE# 1
BBED> set block 1
BLOCK# 1
BBED> map
File: /u01/app/oracle/oradata/test1212/system01.dbf (1)
Block: 1 Dba:0x00400001
------------------------------------------------------------
Data File Header
struct kcvfh, 860 bytes @0
ub4 tailchk @8188

BBED> dump
File: /u01/app/oracle/oradata/test1212/system01.dbf (1)
Block: 1 Offsets: 0 to 511 Dba:0x00400001
------------------------------------------------------------------------
0ba20000 01004000 00000000 00000104 fae40000 00000000 0000200b 021aedcf
54455354 31323132 30050000 00540100 00200000 01000300 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
08024000 07000000 00000000 25316a29 04864d31 38830b00 00000000 00000000
00000000 00000000 00000420 97000000 25f6ff31 96000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 06005359 5354454d 00000000 00000000
00000000 00000000 00000000 00000000 01000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 0a000a00
20316a29 01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 7b281100 000093bf fd660132 0100775b 39000000 02000000 10005d10

<32 bytes per line>


根据实验总结出来的结论为向导,找到第 28-31 个字节和第 32-39 个字节的信息:
第 28-31 个字节:"021aedcf",根据之前提到的字节顺序存放的知识,我们做如下的操作:
021aedcf 取反==》 0xcfed1a02
SQL> select to_number('cfed1a02','xxxxxxxx') from dual;
TO_NUMBER('CFED1A02','XXXXXXXX')
--------------------------------
3488422402

--可以很清楚的看到 021aedcf 取反再转化成 10 进制数所得到的结果是 3488422402,而这个


正好和通过 sql 查询出来的 dbid 是一样的!

可以很清楚的看到 021aedcf 取反再转化成 10 进制数所得到的结果是 3488422402,而这个


正好和通过 sql 查询出来的 dbid 是一样的!

而第 32-39 个字节的信息:"54455354 31323132",我们通过一个 sql 来查询这一串字符到底


代表的是什么:
SQL> select chr(to_number((substr(replace('54455354 31323132',' '),rownum*2-1,2)), 'xxxxxxxx
xxx')) from v$mystat where rownum <9;
CH
--
T
E
S
T
1
2
1
2

通过结果我们也可以发现"54455354 31323132"原来对应的就是我们的 sid。

另外,我们可以通过 bbed 继续观察:


BBED> map /v
File: /u01/app/oracle/oradata/test1212/system01.dbf (1)
Block: 1 Dba:0x00400001
------------------------------------------------------------
Data File Header
struct kcvfh, 860 bytes @0
struct kcvfhbfh, 20 bytes @0
struct kcvfhhdr, 76 bytes @20
ub4 kcvfhrdb @96
struct kcvfhcrs, 8 bytes @100
ub4 kcvfhcrt @108
ub4 kcvfhrlc @112
struct kcvfhrls, 8 bytes @116
ub4 kcvfhbti @124
struct kcvfhbsc, 8 bytes @128
ub2 kcvfhbth @136
ub2 kcvfhsta @138
struct kcvfhckp, 36 bytes @484

ub4 tailchk @8188

我们已经知道 dbid 的信息存放在块的第 28-31 个字节,而 sid 的信息存放在第 32-39 个字节


中,那么我们可以观察到这个信息其实就是放在结构 struct kcvfhhdr, 76 bytes @20 中的
(位于@20-@96 这 2 个之间)

再继续查看 kcvfhhdr 的详细信息:


BBED> print kcvfhhdr
struct kcvfhhdr, 76 bytes @20
ub4 kccfhswv @20 0x00000000
ub4 kccfhcvn @24 0x0b200000
ub4 kccfhdbi @28 0xcfed1a02
text kccfhdbn[0] @32 T
text kccfhdbn[1] @33 E
text kccfhdbn[2] @34 S
text kccfhdbn[3] @35 T
text kccfhdbn[4] @36 1
text kccfhdbn[5] @37 2
text kccfhdbn[6] @38 1
text kccfhdbn[7] @39 2
ub4 kccfhcsq @40 0x00000530
ub4 kccfhfsz @44 0x00015400
s_blkz kccfhbsz @48 0x00
ub2 kccfhfno @52 0x0001
ub2 kccfhtyp @54 0x0003
ub4 kccfhacid @56 0x00000000
ub4 kccfhcks @60 0x00000000
text kccfhtag[0] @64
text kccfhtag[1] @65
text kccfhtag[2] @66
text kccfhtag[3] @67
text kccfhtag[4] @68
text kccfhtag[5] @69
text kccfhtag[6] @70
text kccfhtag[26] @90
text kccfhtag[27] @91
text kccfhtag[28] @92
text kccfhtag[29] @93
text kccfhtag[30] @94
text kccfhtag[31] @95

这下更能清楚的看到:
ub4 kccfhdbi @28 0xcfed1a02
text kccfhdbn[0] @32 T
text kccfhdbn[1] @33 E
text kccfhdbn[2] @34 S
text kccfhdbn[3] @35 T
text kccfhdbn[4] @36 1
text kccfhdbn[5] @37 2
text kccfhdbn[6] @38 1
text kccfhdbn[7] @39 2

第 28 到 31 的是“0xcfed1a02”,也就是我们之前已经算出来的 dbid 的十六进制结果;


而第 32 到 39 更能直观的看到 sid 的显示。也间接的告诉了我们,sid 只有 8 个 bit 来存放,
这些都是块格式中规定好了的,所以有些想把 sid 的长度定义超过 8 位的想法是不现实的。

You might also like