Gomdol Kim

rousalome.egloos.com

포토로그



[Linux][Debug][T32] macro offsetof/container_of 리눅스 커널

Overview
When debugging ramdump with stability issues, I have been spending most of time casting various data structure as belows.
v.v %s (struct task_struct*)0xC1917FCC
For this matter, I made several macros to minimize the debugging time.
The definition of the macro is below.
sYmbol.NEW.MACRO offsetof(type,member) ((int)(&((type*)0)->member))
sYmbol.NEW.MACRO container_of(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member)))

offsetof(type,member)
When analyzing assembly code, I have to know the offset of certain element, assembly code is generated based upon offset value of data structure.
[1]: offset: struct kgsl_context.device is calculated as 0x1C
v.v % offsetof(struct kgsl_context,device)
  (int) offsetof(struct kgsl_context,device) = 28 = 0x1C = '....'
[assemble code]
NSR:C0500F68|E594501C                                  ldr     r5,[r4,#0x1C]

[2]: offset: struct adreno_context.rb
v.v % offsetof(struct adreno_context,rb)
  (int) offsetof(struct adreno_context,rb) = 768 = 0x0300 = '....'
[assemble code]
NSR:C0501054|E5943300                                  ldr     r3,[r4,#0x300]

Code segment for this example
449void adreno_drawctxt_detach(struct kgsl_context *context)
450{
451 struct kgsl_device *device;
452 struct adreno_device *adreno_dev;
453 struct adreno_context *drawctxt;
454 struct adreno_ringbuffer *rb;
455 int ret, count, i;
456 struct kgsl_cmdbatch *list[ADRENO_CONTEXT_CMDQUEUE_SIZE];
//snip
460
461 device = context->device;  // <<--[1]
462 adreno_dev = ADRENO_DEVICE(device);
463 drawctxt = ADRENO_CONTEXT(context);
 464 rb = drawctxt->rb; // <<--[2]
465

container_of(ptr,type,member)
(Example1)
In order to find out the total element of "struct task_struct" as per "struct task_struct.tasks.next",
I have to manipulate the T32 many times. For this, let me introduce the container_of(ptr,type,member) macro
v.v %h container_of(0xEE458238,struct task_struct,tasks)
  container_of(0xEE458238,struct task_struct,tasks) = 0xEE458000 -> (
    state = 0x1,
    stack = 0xEE44A000,
//snip
    cputime_expires = (utime = 0x0, stime = 0x0, sum_exec_runtime = 0x0),
    cpu_timers = ((next = 0xEE458380, prev = 0xEE458380), (next = 0xEE458388, pr
    real_cred = 0xE2494D00,
    cred = 0xE2494D00,
    comm = "init",

(where)
  [D:0xC16141E8] init_task = (
    [D:0xC16141E8] state = 0x0,
    [D:0xC16141EC] stack = 0xC1600000,
//snip
    [D:0xC161441C] rcu_blocked_node = 0x0,
    [D:0xC1614420] tasks = (
      [D:0xC1614420] next = 0xEE458238,  // <<--
      [D:0xC1614424] prev = 0xC288B938),
    [D:0xC1614428] pushable_tasks = ([D:0xC1614428] prio = 0x8C, [D:0xC161442C] prio_list = ([D:0xC161442C] next = 0x
//snip
    [D:0xC1614584] cred = 0xC1619D18,
    [D:0xC1614588] comm = "swapper/0",
    [D:0xC1614598] link_count = 0x0,
    [D:0xC161459C] total_link_count = 0x0,

v.v %h %s container_of(0xDB63FE68,struct mutex,wait_list)
  container_of(0xDB63FE68,struct mutex,wait_list) = 0xDB63FE54 -> (
    count = (counter = 0xC0C0A56C),
    wait_lock = (rlock = (raw_lock = (slock = 0xC16A057C, tickets = (owner = 0x057C, next = 0xC16A)), magic = 0xC0C08C70, o
    wait_list = (next = 0xDAC43DB8, prev = 0xC15DBC40),
    owner = 0xE0396E00,
    name = 0xDB63FE68 -> ".=..@.].",
    magic = 0xFFFFFFFF)

  container_of(0xDAC43DB8,struct mutex,wait_list) = 0xDAC43DA4 -> (
    count = (counter = 0xC0C0A56C),
    wait_lock = (rlock = (raw_lock = (slock = 0xC16A057C, tickets = (owner = 0x0
    wait_list = (next = 0xDAC55E68, prev = 0xDB63FE68),
    owner = 0xDD5C5D80,
    name = 0xDAC43DB8 -> "h^..h.c..]\..=..``v.,.].",
    magic = 0xDB766060)

(where)  binder_main_lock = (
    count = (counter = 0xFFFFFFFF),
    wait_lock = (rlock = (raw_lock = (slock = 0xF1CCF1CC, tickets = (owner = 0xF
    wait_list = (
      next = 0xDB63FE68 // <<--
        next = 0xDAC43DB8 // <<--
          next = 0xDAC55E68 -> (
            next = 0xC15DBC40 -> (
              next = 0xDB63FE68,

container_of_double_vcast(ptr,type,member,new_member,cast_type)
Definition
sYmbol.NEW.MACRO container_double_vcast(ptr,type,member,new_member,cast_type) ((cast_type *)(*(type *)((char *)(ptr)-offsetof(type,member)+offsetof(type,new_member))))
(Example1: PHONEMODEL-1958)
container_of_double_vcast(0xDAC43DB8,struct mutex,wait_list,owner,struct task_struct)
  container_of_double_vcast(0xDAC43DB8,struct mutex,wait_list,owner,struct task_struct) = 0xDD5C5D80 -> (
    state = 0x2,
    stack = 0xDAC42000,
    usage = (counter = 0x2),
    flags = 0x00400040,
    ptrace = 0x0,
    wake_entry = (next = 0x0),
    on_cpu = 0x0,
    on_rq = 0x0,
    prio = 0x78,
    static_prio = 0x78,

(where)
  binder_main_lock = (  // <<-- type: struct mutex
    count = (counter = 0xFFFFFFFF),
    wait_lock = (rlock = (raw_lock = (slock = 0xF1CCF1CC, tickets = (owner = 0xF
    wait_list // <<-- member
      next = 0xDB63FE68 
        next = 0xDAC43DB8 // <<--  ptr
          next = 0xDAC55E68 -> (
            next = 0xC15DBC40 -> (
              next = 0xDB63FE68,
              prev = 0xDAC55E68),
            prev = 0xDAC43DB8),
          prev = 0xDB63FE68),
        prev = 0xC15DBC40),
      prev = 0xDAC55E68),
    owner = 0xD9E6A100,  // <<-- new_member, cast_type: struct task_struct
    name = 0x0,
    magic = 0xC15DBC2C)

container_down_vcast(ptr,type,member,cast)
Definition
sYmbol.NEW.MACRO container_down_vcast(ptr,type,member,cast) ((cast *)(*(type *)((char *)(ptr)+offsetof(type,member))))

v.v % container_down_vcast(0xC15DBC2C,struct mutex,owner,struct task_struct)
v.v % container_down_vcast(0xC15DBC2C,struct mutex,owner,struct task_struct)
  container_down_vcast(0xC15DBC2C,struct mutex,owner,struct task_struct) = 0xD9E6A100 -> (
    state = 1,
    stack = 0xD9ECC000,
    usage = (counter = 2),
//snip
    min_flt = 304,
    maj_flt = 0,
    cputime_expires = (utime = 0, stime = 0, sum_exec_runtime = 0),
    cpu_timers = ((next = 0xD9E6A448, prev = 0xD9E6A448), (next = 0xD9E6A450, prev = 0xD9E6A450), (next = 0xD9E6A45
    real_cred = 0xDEEF1900,
    cred = 0xDEEF1900,
    comm = "Binder_4",
    link_count = 0,

(where)
  [D:0xC15DBC2C] binder_main_lock = (  // <<-- ptr: 0xC15DBC2C, type: struct mutex
    [D:0xC15DBC2C] count = ([D:0xC15DBC2C] counter = -1),
    [D:0xC15DBC30] wait_lock = ([D:0xC15DBC30] rlock = ([D:0xC15DBC30] raw_lock
    [D:0xC15DBC40] wait_list = ([D:0xC15DBC40] next = 0xDB63FE68, [D:0xC15DBC44]
    [D:0xC15DBC48] owner = 0xD9E6A100,  // <<--member, cast: struct task_struct
    [D:0xC15DBC4C] name = 0x0,
    [D:0xC15DBC50] magic = 0xC15DBC2C)

threadoffset(ptr)
Definition
sYmbol.NEW.MACRO threadoffset(ptr) ((ptr ~0x1fff))
sYmbol.NEW.MACRO thread_of(ptr) ((struct thread_info *)((int *)threadoffset(ptr)))
When kernel crash occurs, the kernel dumps below logs
[ 1894.897301] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM
[ 1894.897314] Modules linked in: texfat(PO)
[ 1894.897333] CPU: 2 PID: 4324 Comm: Binder_4 Tainted: P        W  O 3.10.49-g184f2e4 #1
[ 1894.897347] task: d9e6a100 ti: d9ecc000 task.ti: d9ecc000
[ 1894.897362] PC is at __list_add+0x9c/0xd0
[ 1894.897376] LR is at __list_add+0x58/0xd0
[ 1894.897390] pc : [<c032e9e8>]    lr : [<c032e9a4>]    psr: 000f0093
[ 1894.897390] sp : d9ecdd90  ip : 00000000  fp : dc08da00
[ 1894.897409] r10: d9ecc000  r9 : c16a39ec  r8 : d9e6a100
[ 1894.897422] r7 : 00000000  r6 : d9ecddb8  r5 : c15dbc40  r4 : c0004860
[ 1894.897435] r3 : 00000000  r2 : 00001201  r1 : c16a28a8  r0 : 00000000
[ 1894.897450] Flags: nzcv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
[ 1894.897464] Control: 10c0383d  Table: 9e06006a  DAC: 00000015
[ 1894.897476] Process Binder_4 (pid: 4324, stack limit = 0xd9ecc238)
[ 1894.897489] Stack: (0xd9ecdd90 to 0xd9ece000)
[ 1894.897504] dd80:                                     00000000 c0004860 c15dbc40 c15dbc2c
[ 1894.897522] dda0: 600f0013 d9ecc030 c15dbc30 c0c08bcc d9ecdddc c15dbc40 d9ecddb8 d9ecddb8
[ 1894.897540] ddc0: 11111111 d9ecddb8 600f0013 c15dbc2c de364e00 b786a844 d9ecc038 c1660598
[ 1894.897557] dde0: 00000000 d9ecc000 dc08da00 c0c08e70 ddf0f000 c072d020 ded48000 c018b544
[ 1894.897574] de00: 00000000 800f0193 00000028 dd041600 c8002ab0 b781ee04 00000000 db0d1c00
[ 1894.897591] de20: c8002ad0 00000000 00000000 b786a840 b786a940 ddf0f01c d9ecdee0 d9ecc000

With any stack address, the (struct thread_info*) can be casted with the single command.
v.v %all thread_of(0xd9ecdd90)
  (struct thread_info *) thread_of(0xd9ecdd90) = 0xD9ECC000 = __bss_stop+0x1855F
    (long unsigned int) flags = 0 = 0x0 = '....',
    (int) preempt_count = 3 = 0x3 = '....',
    (mm_segment_t) addr_limit = 3204448256 = 0xBF000000 = '....',
    (struct task_struct *) task = 0xD9E6A100 = __bss_stop+0x184FD964 -> ((long i
    (struct exec_domain *) exec_domain = 0xC1579CDC = default_exec_domain -> ((c
    (__u32) cpu = 2 = 0x2 = '....',
    (__u32) cpu_domain = 21 = 0x15 = '....',
    (struct cpu_context_save) cpu_context = ((__u32) r4 = 3740230976 = 0xDEEF654
    (__u32) syscall = 0 = 0x0 = '....',
    (__u8 [16]) used_cp = "",
    (long unsigned int [2]) tp_value = ([0] = 3001371000 = 0xB2E54978 = '..Ix',
    (union fp_state) fpstate = ((struct fp_hard_struct) hard = ((unsigned int [3
    (union vfp_state) vfpstate = ((struct vfp_hard_struct) hard = ((__u64 [32])
    (struct restart_block) restart_block = ((long int (*)()) fn = 0xC0131A64 = d

v.v %all thread_of(0xd9ecddc0)
  (struct thread_info *) thread_of(0xd9ecddc0) = 0xD9ECC000 = __bss_stop+0x1855F
    (long unsigned int) flags = 0 = 0x0 = '....',
    (int) preempt_count = 3 = 0x3 = '....',
    (mm_segment_t) addr_limit = 3204448256 = 0xBF000000 = '....',
    (struct task_struct *) task = 0xD9E6A100 = __bss_stop+0x184FD964 -> ((long i
    (struct exec_domain *) exec_domain = 0xC1579CDC = default_exec_domain -> ((c
    (__u32) cpu = 2 = 0x2 = '....',
    (__u32) cpu_domain = 21 = 0x15 = '....',
    (struct cpu_context_save) cpu_context = ((__u32) r4 = 3740230976 = 0xDEEF654
    (__u32) syscall = 0 = 0x0 = '....',
    (__u8 [16]) used_cp = "",
    (long unsigned int [2]) tp_value = ([0] = 3001371000 = 0xB2E54978 = '..Ix',
    (union fp_state) fpstate = ((struct fp_hard_struct) hard = ((unsigned int [3
    (union vfp_state) vfpstate = ((struct vfp_hard_struct) hard = ((__u64 [32])
    (struct restart_block) restart_block = ((long int (*)()) fn = 0xC0131A64 = d


덧글

댓글 입력 영역