1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-08 03:27: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:
Mike McLaughlin 2022-04-07 15:42:31 -07:00 committed by GitHub
parent d43fff4e88
commit dd66c99ea8
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 183 additions and 1 deletions

View file

@ -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
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
-------------------------------------

View file

@ -1310,6 +1310,14 @@ GetProcInfo(unw_word_t ip, unw_proc_info_t *pip, libunwindInfo* info, bool* step
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)
static bool
@ -1381,6 +1389,163 @@ StepWithCompactEncodingRBPFrame(const libunwindInfo* info, compact_unwind_encodi
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, &reg)) {
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
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_IND:
break;
return StepWithCompactEncodingFrameless(info, compactEncoding, functionStart);
case UNWIND_X86_64_MODE_DWARF:
return false;