A basic block is cosidered a sequence of opcodes ended up by a jump/branch/ret instruction. Radare allows you to determine which kind of basic block splitting you want to use to have a more personalized way to read the code and be able to split the functions as basic blocks for example.
Use these variables to configure how the code analysis should work to determine basic blocks:
graph.jmpblocks = true
graph.refblocks = false
graph.callblocks = false
graph.flagblocks = true
The 'ab' command will look for a basic block definition starting at current seek:
[0xB7FC4810]> ab
offset = 0xb7fc4810
type = head
size = 73
call0 = 0xb7fc4a60
call1 = 0xb7fc4800
call2 = 0xb7fd1a40
n_calls = 3
bytes = 89 e0 e8 49 02 00 00 89 c7 e8 e2 ff ff ff ...
The output is quite parsing friendly, so you can easily use the python API to extract this information:
[0xB7F14810]> H python
python> block = radare.analyze_block()
python> print "This basic block have %d calls.\n" % radare.block['n_calls']
This basic block have 3 calls.
python> print "Its size is %d bytes.\n" % block['size']
Its size is 74 bytes
There's a human friendly version of 'ab' called 'ac' which stands for 'analyze code'. It accepts a numeric argument to determine the depth level when performing the basic block analysis.
[0xB7F93A60]> ac 10
0xb7f93a60 (0) -> 0xb7f93ae1, 0xb7f93a99
0xB7F93A60, eip: push ebp
0xB7F93A61 ebp = esp
0xB7F93A63 push edi
...
0xB7F93A8F [ebx+0x2b4] = eax
0xB7F93A95 test edx, edx
0xB7F93A97 v jz 0xB7F93AE1 ; 2 = eip+0x7b
0xb7f93ae1 (0) -> 0xb7f93b53, 0xb7f93aeb
0xB7F93AE1 edx = [ebx+0x2ac]
0xB7F93AE7 test edx, edx
0xB7F93AE9 v jz 0xB7F93B53 ; 1
0xb7f93b53 (0) -> 0xb7f93b67, 0xb7f93b5d
0xB7F93B53 eax = [ebx+0x31c]
0xB7F93B59 test eax, eax
.==< 0xB7F93B5B v jz 0xB7F93B67 ; 1 = eip+0x107
0xb7f93b67 (0) -> 0xb7f93b81, 0xb7f93b71
0xB7F93B67 eax = [ebx+0x310]
0xB7F93B6D test eax, eax
.==< 0xB7F93B6F v jz 0xB7F93B81 ; 1 = eip+0x121
...
The values shown are:
address (0) -> true-jump, false-jump