| 112 | } |
| 113 | |
| 114 | int StackWalker::walkDwarf(void* ucontext, const void** callchain, int max_depth) { |
| 115 | const void* pc; |
| 116 | uintptr_t fp; |
| 117 | uintptr_t sp; |
| 118 | uintptr_t bottom = (uintptr_t)&sp + MAX_WALK_SIZE; |
| 119 | |
| 120 | StackFrame frame(ucontext); |
| 121 | if (ucontext == NULL) { |
| 122 | pc = callerPC(); |
| 123 | fp = (uintptr_t)callerFP(); |
| 124 | sp = (uintptr_t)callerSP(); |
| 125 | } else { |
| 126 | pc = (const void*)frame.pc(); |
| 127 | fp = frame.fp(); |
| 128 | sp = frame.sp(); |
| 129 | } |
| 130 | |
| 131 | int depth = 0; |
| 132 | Profiler* profiler = Profiler::instance(); |
| 133 | |
| 134 | // Walk until the bottom of the stack or until the first Java frame |
| 135 | while (depth < max_depth) { |
| 136 | if (CodeHeap::contains(pc) && !(depth == 0 && frame.unwindAtomicStub(pc))) { |
| 137 | break; |
| 138 | } |
| 139 | |
| 140 | callchain[depth++] = pc; |
| 141 | |
| 142 | uintptr_t prev_sp = sp; |
| 143 | CodeCache* cc = profiler->findLibraryByAddress(pc); |
| 144 | FrameDesc* f = cc != NULL ? cc->findFrameDesc(pc) : &FrameDesc::default_frame; |
| 145 | |
| 146 | retry_unwind_frame: |
| 147 | u8 cfa_reg = (u8)f->cfa; |
| 148 | int cfa_off = f->cfa >> 8; |
| 149 | if (cfa_reg == DW_REG_SP) { |
| 150 | sp = sp + cfa_off; |
| 151 | } else if (cfa_reg == DW_REG_FP) { |
| 152 | sp = fp + cfa_off; |
| 153 | } else if (cfa_reg == DW_REG_PLT) { |
| 154 | sp += ((uintptr_t)pc & 15) >= 11 ? cfa_off * 2 : cfa_off; |
| 155 | } else { |
| 156 | break; |
| 157 | } |
| 158 | |
| 159 | // Check if the next frame is below on the current stack |
| 160 | if (sp < prev_sp || sp >= prev_sp + MAX_FRAME_SIZE || sp >= bottom) { |
| 161 | break; |
| 162 | } |
| 163 | |
| 164 | // Stack pointer must be word aligned |
| 165 | if (!aligned(sp)) { |
| 166 | break; |
| 167 | } |
| 168 | |
| 169 | const void* prev_pc = pc; |
| 170 | if (f->fp_off & DW_PC_OFFSET) { |
| 171 | pc = (const char*)pc + (f->fp_off >> 1); |
nothing calls this directly
no test coverage detected