The blog.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

121 lines
4.5 KiB

  1. ---
  2. title: "CTF + ARMeb + debugging"
  3. description: >
  4. CTF + ARMeb + debugging
  5. posted: !!timestamp '2014-03-05'
  6. created: !!timestamp '2014-03-05'
  7. time: 7:21 PM
  8. tags:
  9. - ctf
  10. - debugging
  11. - arm
  12. ---
  13. I've been working on making the AVILA board work again with FreeBSD.
  14. Thanks to Jim from Netgate for sending me a board to do this work.
  15. I still have a pending patch waiting to go through bde to fix an
  16. unaligned off_t store which gets things farther, but with the patch I'm
  17. getting a: `panic: vm_page_alloc: page 0xc0805db0 is wired` shortly after
  18. the machine launches the daemons.
  19. I did work to get cross gdb working for armeb (committed in r261787 and
  20. r261788), but that didn't help as there is no kernel gdb support on
  21. armeb. As I'm doing this debugging over the network, I can't dump a
  22. core.
  23. I didn't feel like hand decoding a `struct vm_page`, so I thought of other
  24. methods, and one way is to use CTF to parse the data type and decode the
  25. data. I know python and ctypes, so I decided to wrap libctf and see
  26. what I could do.
  27. Getting the initial python wrapper working was easy, but my initial test
  28. data was the kernel on my amd64 box that I am developing on. Now I
  29. needed to use real armeb CTF data. I point it to my kernel, and I get:
  30. "`File uses more recent ELF version than libctf`". Ok, extract the CTF
  31. data from the kernel (ctf data is stored in a section named `.SUNW_ctf`)
  32. and work on that directly:
  33. ```
  34. $ objcopy -O binary --set-section-flags optfiles=load,alloc -j .SUNW_ctf /tftpboot/kernel.avila.avila /dev/null
  35. objcopy: /tftpboot/kernel.avila.avila: File format not recognized
  36. ```
  37. Well, ok, that's not too surprising since it's an ARMEB binary, lets try:
  38. ```
  39. $ /usr/obj/arm.armeb/usr/src.avila/tmp/usr/bin/objcopy -O binary --set-section-flags optfiles=load,alloc -j .SUNW_ctf /tftpboot/kernel.avila.avila /tmp/test.avila.ctf
  40. $ ls -l /tmp/test.avila.ctf
  41. -rwxr-xr-x 1 jmg wheel 0 Mar 5 17:59 /tmp/test.avila.ctf
  42. ```
  43. Hmm, that didn't work too well, ok, lets just use dd to extract the data
  44. using info from `objdump -x`.
  45. Ok, now that I've done that, I get:
  46. ```
  47. ValueError: '/tmp/avila.ctf': File is not in CTF or ELF format
  48. ```
  49. Hmm, why is that? Well, it turns out that the endian of the CTF data
  50. is wrong. The magic is `cf f1`, but the magic on amd64 is `f1 cf`, it's
  51. endian swapped. That's annoying. After spending some time trying to
  52. build an cross shared version of libctf, I find that it has the same
  53. issue.
  54. After a bit of looking around, I discover the CTF can only ever read
  55. native endianness, but `ctfmerge` has a magic option that will write out
  56. endian swapped data if necessary depending upon the ELF file it's
  57. putting in. This means that the CTF data in an armeb object file will
  58. be different depending upon the endian you compiled it on, so the object
  59. file isn't cross compatible. But, this does mean that the data in the
  60. object files will be readable by libctf, just not the data written into
  61. the kernel.
  62. So, I create a sacrificial amd64 binary:
  63. ```
  64. $ echo 'int main() {}' | cc -o /tmp/avila2.ctf -x c -
  65. ```
  66. And use `ctfmerge` to put the data in it:
  67. ```
  68. $ ctfmerge -L fldkj -o /tmp/avila2.ctf /usr/obj/arm.armeb/usr/src.avila/sys/AVILA/*.o
  69. ```
  70. and again use `dd` to extract the `.SUNW_ctf` section into a separate file.
  71. With all this work, I finally have the CTF data in a format that libctf
  72. can parse, so, I try to parse some data. Now the interesting thing is
  73. that the CTF data does encode sizes of integers, but it uses the native
  74. arch's pointer sizes for `CTF_K_POINTER` types, which means that pointers
  75. appear to be 8 bytes in size instead of the correct 4 bytes. A little
  76. more hacking on the ctf.py script to force all pointers to be 4 bytes,
  77. and a little help to convert ddb output to a string and finally, I have
  78. a dump of the <code>struct&nbsp;vm_page</code> that I was trying to get all along:
  79. ```
  80. {'act_count': '\x00',
  81. 'aflags': '\x00',
  82. 'busy_lock': 1,
  83. 'dirty': '\xff',
  84. 'flags': 0,
  85. 'hold_count': 0,
  86. 'listq': {'tqe_next': 0xc0805e00, 'tqe_prev': 0xc06d18a0},
  87. 'md': {'pv_kva': 3235856384,
  88. 'pv_list': {'tqh_first': 0x0, 'tqh_last': 0xc0805de0},
  89. 'pv_memattr': '\x00',
  90. 'pvh_attrs': 0},
  91. 'object': 0xc06d1878,
  92. 'oflags': '\x04',
  93. 'order': '\t',
  94. 'phys_addr': 17776640,
  95. 'pindex': 3572,
  96. 'plinks': {'memguard': {'p': 0, 'v': 3228376932},
  97. 'q': {'tqe_next': 0x0, 'tqe_prev': 0xc06d1f64},
  98. 's': {'pv': 0xc06d1f64, 'ss': {'sle_next': 0x0}}},
  99. 'pool': '\x00',
  100. 'queue': '\xff',
  101. 'segind': '\x01',
  102. 'valid': '\xff',
  103. 'wire_count': 1}
  104. ```
  105. So, the above was produced w/ the final [ctf.py](https://www.funkthat.com/~jmg/ctf.py) script.