mirror of
https://github.com/VSadov/Satori.git
synced 2025-06-08 11:37:04 +09:00
VS4Mac crash reports on MacOS v12 (Monterey) are missing native stack frames. (#67713)
Can not properly triage VS4Mac failures. The amd64 frameless compact encoding is being used now in MacOS version 12 and needed to be implemented. Issue: https://github.com/dotnet/diagnostics/issues/2924
This commit is contained in:
parent
d43fff4e88
commit
dd66c99ea8
2 changed files with 183 additions and 1 deletions
|
@ -967,6 +967,23 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
|
License for remote stack unwind (https://github.com/llvm/llvm-project/blob/main/lldb/source/Symbol/CompactUnwindInfo.cpp)
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
Copyright 2019 LLVM Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License") with LLVM Exceptions;
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
https://llvm.org/LICENSE.txt
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
License notice for Apple header files
|
License notice for Apple header files
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -1310,6 +1310,14 @@ GetProcInfo(unw_word_t ip, unw_proc_info_t *pip, libunwindInfo* info, bool* step
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===-- CompactUnwindInfo.cpp ---------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#if defined(TARGET_AMD64)
|
#if defined(TARGET_AMD64)
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -1381,6 +1389,163 @@ StepWithCompactEncodingRBPFrame(const libunwindInfo* info, compact_unwind_encodi
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
StepWithCompactEncodingFrameless(const libunwindInfo* info, compact_unwind_encoding_t compactEncoding, unw_word_t functionStart)
|
||||||
|
{
|
||||||
|
int mode = compactEncoding & UNWIND_X86_64_MODE_MASK;
|
||||||
|
CONTEXT* context = info->Context;
|
||||||
|
|
||||||
|
uint32_t stack_size = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
|
||||||
|
uint32_t register_count = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
|
||||||
|
uint32_t permutation = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
|
||||||
|
|
||||||
|
if (mode == UNWIND_X86_64_MODE_STACK_IND)
|
||||||
|
{
|
||||||
|
_ASSERTE(functionStart != 0);
|
||||||
|
unw_word_t addr = functionStart + stack_size;
|
||||||
|
if (!ReadValue32(info, &addr, &stack_size)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint32_t stack_adjust = EXTRACT_BITS(compactEncoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
|
||||||
|
stack_size += stack_adjust * 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stack_size *= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("Frameless function: encoding %08x stack size %d register count %d\n", compactEncoding, stack_size, register_count);
|
||||||
|
|
||||||
|
// We need to include (up to) 6 registers in 10 bits.
|
||||||
|
// That would be 18 bits if we just used 3 bits per reg to indicate
|
||||||
|
// the order they're saved on the stack.
|
||||||
|
//
|
||||||
|
// This is done with Lehmer code permutation, e.g. see
|
||||||
|
// http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
|
||||||
|
int permunreg[6];
|
||||||
|
|
||||||
|
// This decodes the variable-base number in the 10 bits
|
||||||
|
// and gives us the Lehmer code sequence which can then
|
||||||
|
// be decoded.
|
||||||
|
switch (register_count) {
|
||||||
|
case 6:
|
||||||
|
permunreg[0] = permutation / 120; // 120 == 5!
|
||||||
|
permutation -= (permunreg[0] * 120);
|
||||||
|
permunreg[1] = permutation / 24; // 24 == 4!
|
||||||
|
permutation -= (permunreg[1] * 24);
|
||||||
|
permunreg[2] = permutation / 6; // 6 == 3!
|
||||||
|
permutation -= (permunreg[2] * 6);
|
||||||
|
permunreg[3] = permutation / 2; // 2 == 2!
|
||||||
|
permutation -= (permunreg[3] * 2);
|
||||||
|
permunreg[4] = permutation; // 1 == 1!
|
||||||
|
permunreg[5] = 0;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
permunreg[0] = permutation / 120;
|
||||||
|
permutation -= (permunreg[0] * 120);
|
||||||
|
permunreg[1] = permutation / 24;
|
||||||
|
permutation -= (permunreg[1] * 24);
|
||||||
|
permunreg[2] = permutation / 6;
|
||||||
|
permutation -= (permunreg[2] * 6);
|
||||||
|
permunreg[3] = permutation / 2;
|
||||||
|
permutation -= (permunreg[3] * 2);
|
||||||
|
permunreg[4] = permutation;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
permunreg[0] = permutation / 60;
|
||||||
|
permutation -= (permunreg[0] * 60);
|
||||||
|
permunreg[1] = permutation / 12;
|
||||||
|
permutation -= (permunreg[1] * 12);
|
||||||
|
permunreg[2] = permutation / 3;
|
||||||
|
permutation -= (permunreg[2] * 3);
|
||||||
|
permunreg[3] = permutation;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
permunreg[0] = permutation / 20;
|
||||||
|
permutation -= (permunreg[0] * 20);
|
||||||
|
permunreg[1] = permutation / 4;
|
||||||
|
permutation -= (permunreg[1] * 4);
|
||||||
|
permunreg[2] = permutation;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
permunreg[0] = permutation / 5;
|
||||||
|
permutation -= (permunreg[0] * 5);
|
||||||
|
permunreg[1] = permutation;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
permunreg[0] = permutation;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the Lehmer code for this permutation of
|
||||||
|
// the registers v. http://en.wikipedia.org/wiki/Lehmer_code
|
||||||
|
int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
|
||||||
|
UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
|
||||||
|
UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE};
|
||||||
|
bool used[7] = {false, false, false, false, false, false, false};
|
||||||
|
for (int i = 0; i < register_count; i++)
|
||||||
|
{
|
||||||
|
int renum = 0;
|
||||||
|
for (int j = 1; j < 7; j++)
|
||||||
|
{
|
||||||
|
if (!used[j])
|
||||||
|
{
|
||||||
|
if (renum == permunreg[i])
|
||||||
|
{
|
||||||
|
registers[i] = j;
|
||||||
|
used[j] = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
renum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t savedRegisters = context->Rsp + stack_size - 8 - (8 * register_count);
|
||||||
|
for (int i = 0; i < register_count; i++)
|
||||||
|
{
|
||||||
|
uint64_t reg;
|
||||||
|
if (!ReadValue64(info, &savedRegisters, ®)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (registers[i]) {
|
||||||
|
case UNWIND_X86_64_REG_RBX:
|
||||||
|
context->Rbx = reg;
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_R12:
|
||||||
|
context->R12 = reg;
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_R13:
|
||||||
|
context->R13 = reg;
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_R14:
|
||||||
|
context->R14 = reg;
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_R15:
|
||||||
|
context->R15 = reg;
|
||||||
|
break;
|
||||||
|
case UNWIND_X86_64_REG_RBP:
|
||||||
|
context->Rbp = reg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR("Bad register for frameless\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now unwind the frame
|
||||||
|
uint64_t ip;
|
||||||
|
if (!ReadValue64(info, &savedRegisters, &ip)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
context->Rip = ip;
|
||||||
|
context->Rsp = savedRegisters;
|
||||||
|
|
||||||
|
TRACE("SUCCESS: frameless encoding %08x rip %p rsp %p rbp %p\n",
|
||||||
|
compactEncoding, (void*)context->Rip, (void*)context->Rsp, (void*)context->Rbp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#define AMD64_SYSCALL_OPCODE 0x050f
|
#define AMD64_SYSCALL_OPCODE 0x050f
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -1602,7 +1767,7 @@ StepWithCompactEncoding(const libunwindInfo* info, compact_unwind_encoding_t com
|
||||||
|
|
||||||
case UNWIND_X86_64_MODE_STACK_IMMD:
|
case UNWIND_X86_64_MODE_STACK_IMMD:
|
||||||
case UNWIND_X86_64_MODE_STACK_IND:
|
case UNWIND_X86_64_MODE_STACK_IND:
|
||||||
break;
|
return StepWithCompactEncodingFrameless(info, compactEncoding, functionStart);
|
||||||
|
|
||||||
case UNWIND_X86_64_MODE_DWARF:
|
case UNWIND_X86_64_MODE_DWARF:
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue