https://github.com/mylai-mtk updated https://github.com/llvm/llvm-project/pull/126663
>From 39731df5b3e48fe2623786b120dc0eae604f8de6 Mon Sep 17 00:00:00 2001 From: Ming-Yi Lai <ming-yi....@mediatek.com> Date: Tue, 11 Feb 2025 11:20:42 +0800 Subject: [PATCH 1/3] [libunwind][NFC] Remove the CET keyword in shadow stack-related stuffs libunwind currently supports shadow stack based on the Intel CET and AArch64 GCS technology, but throughout related codes, the Intel-specific keyword, "CET", is used to refer to the generic concept of control-flow integrity/shadow stack. This patch replaces such wordings with architecture-neutral term "shadow stack" (abbr. "ss") to allow future implementation to avoid using the Intel-specific "CET" term. --- libunwind/src/CMakeLists.txt | 2 +- libunwind/src/Registers.hpp | 8 +-- libunwind/src/UnwindCursor.hpp | 4 +- libunwind/src/UnwindLevel1.c | 63 ++++++++++--------- .../{cet_unwind.h => shadow_stack_unwind.h} | 12 ++-- 5 files changed, 46 insertions(+), 43 deletions(-) rename libunwind/src/{cet_unwind.h => shadow_stack_unwind.h} (88%) diff --git a/libunwind/src/CMakeLists.txt b/libunwind/src/CMakeLists.txt index ecbd019bb29ea..3bbbc70fde79b 100644 --- a/libunwind/src/CMakeLists.txt +++ b/libunwind/src/CMakeLists.txt @@ -36,7 +36,7 @@ set(LIBUNWIND_HEADERS AddressSpace.hpp assembly.h CompactUnwinder.hpp - cet_unwind.h + shadow_stack_unwind.h config.h dwarf2.h DwarfInstructions.hpp diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index 861e6b5f6f2c5..df79f0439ae85 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -15,7 +15,7 @@ #include <stdint.h> #include <string.h> -#include "cet_unwind.h" +#include "shadow_stack_unwind.h" #include "config.h" #include "libunwind.h" @@ -48,7 +48,7 @@ class _LIBUNWIND_HIDDEN Registers_x86; extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *); #if defined(_LIBUNWIND_USE_CET) -extern "C" void *__libunwind_cet_get_jump_target() { +extern "C" void *__libunwind_ss_get_jump_target() { return reinterpret_cast<void *>(&__libunwind_Registers_x86_jumpto); } #endif @@ -268,7 +268,7 @@ class _LIBUNWIND_HIDDEN Registers_x86_64; extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *); #if defined(_LIBUNWIND_USE_CET) -extern "C" void *__libunwind_cet_get_jump_target() { +extern "C" void *__libunwind_ss_get_jump_target() { return reinterpret_cast<void *>(&__libunwind_Registers_x86_64_jumpto); } #endif @@ -1817,7 +1817,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64; extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *); #if defined(_LIBUNWIND_USE_GCS) -extern "C" void *__libunwind_cet_get_jump_target() { +extern "C" void *__libunwind_ss_get_jump_target() { return reinterpret_cast<void *>(&__libunwind_Registers_arm64_jumpto); } #endif diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index 0923052b1b588..5cb04b1f76820 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -11,7 +11,7 @@ #ifndef __UNWINDCURSOR_HPP__ #define __UNWINDCURSOR_HPP__ -#include "cet_unwind.h" +#include "shadow_stack_unwind.h" #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -3122,7 +3122,7 @@ bool UnwindCursor<A, R>::isReadableAddr(const pint_t addr) const { #endif #if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS) -extern "C" void *__libunwind_cet_get_registers(unw_cursor_t *cursor) { +extern "C" void *__libunwind_ss_get_registers(unw_cursor_t *cursor) { AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->get_registers(); } diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c index 7e785f4d31e71..2d471d5d65690 100644 --- a/libunwind/src/UnwindLevel1.c +++ b/libunwind/src/UnwindLevel1.c @@ -25,7 +25,7 @@ #include <stdio.h> #include <string.h> -#include "cet_unwind.h" +#include "shadow_stack_unwind.h" #include "config.h" #include "libunwind.h" #include "libunwind_ext.h" @@ -36,14 +36,17 @@ #ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND -// When CET is enabled, each "call" instruction will push return address to -// CET shadow stack, each "ret" instruction will pop current CET shadow stack -// top and compare it with target address which program will return. -// In exception handing, some stack frames will be skipped before jumping to -// landing pad and we must adjust CET shadow stack accordingly. -// _LIBUNWIND_POP_CET_SSP is used to adjust CET shadow stack pointer and we -// directly jump to __libunwind_Registers_x86/x86_64_jumpto instead of using -// a regular function call to avoid pushing to CET shadow stack again. +// When shadow stack is enabled, a separate stack containing only return +// addresses would be maintained. On function return, the return address would +// be compared to the popped address from shadow stack to ensure the return +// target is not tempered with. When unwinding, we're skipping the normal return +// procedure for multiple frames and thus need to pop the return addresses of +// the skipped frames from shadow stack to avoid triggering an exception (using +// `_LIBUNWIND_POP_SS_SSP()`). Also, some architectures, like the x86-family +// CET, push the return adddresses onto shadow stack with common call +// instructions, so for these architectures, normal function calls should be +// avoided when invoking the `jumpto()` function. To do this, we use inline +// assemblies to "goto" the `jumpto()` for these architectures. #if !defined(_LIBUNWIND_USE_CET) && !defined(_LIBUNWIND_USE_GCS) #define __unw_phase2_resume(cursor, fn) \ do { \ @@ -51,38 +54,38 @@ __unw_resume((cursor)); \ } while (0) #elif defined(_LIBUNWIND_TARGET_I386) -#define __cet_ss_step_size 4 +#define __shadow_stack_step_size (4) #define __unw_phase2_resume(cursor, fn) \ do { \ - _LIBUNWIND_POP_CET_SSP((fn)); \ - void *cetRegContext = __libunwind_cet_get_registers((cursor)); \ - void *cetJumpAddress = __libunwind_cet_get_jump_target(); \ + _LIBUNWIND_POP_SS_SSP((fn)); \ + void *ssRegContext = __libunwind_ss_get_registers((cursor)); \ + void *ssJumpAddress = __libunwind_ss_get_jump_target(); \ __asm__ volatile("push %%edi\n\t" \ "sub $4, %%esp\n\t" \ - "jmp *%%edx\n\t" :: "D"(cetRegContext), \ - "d"(cetJumpAddress)); \ + "jmp *%%edx\n\t" :: "D"(ssRegContext), \ + "d"(ssJumpAddress)); \ } while (0) #elif defined(_LIBUNWIND_TARGET_X86_64) -#define __cet_ss_step_size 8 +#define __shadow_stack_step_size (8) #define __unw_phase2_resume(cursor, fn) \ do { \ - _LIBUNWIND_POP_CET_SSP((fn)); \ - void *cetRegContext = __libunwind_cet_get_registers((cursor)); \ - void *cetJumpAddress = __libunwind_cet_get_jump_target(); \ - __asm__ volatile("jmpq *%%rdx\n\t" :: "D"(cetRegContext), \ - "d"(cetJumpAddress)); \ + _LIBUNWIND_POP_SS_SSP((fn)); \ + void *ssRegContext = __libunwind_ss_get_registers((cursor)); \ + void *ssJumpAddress = __libunwind_ss_get_jump_target(); \ + __asm__ volatile("jmpq *%%rdx\n\t" :: "D"(ssRegContext), \ + "d"(ssJumpAddress)); \ } while (0) #elif defined(_LIBUNWIND_TARGET_AARCH64) -#define __cet_ss_step_size 8 +#define __shadow_stack_step_size (8) #define __unw_phase2_resume(cursor, fn) \ do { \ - _LIBUNWIND_POP_CET_SSP((fn)); \ - void *cetRegContext = __libunwind_cet_get_registers((cursor)); \ - void *cetJumpAddress = __libunwind_cet_get_jump_target(); \ + _LIBUNWIND_POP_SS_SSP((fn)); \ + void *ssRegContext = __libunwind_ss_get_registers((cursor)); \ + void *ssJumpAddress = __libunwind_ss_get_jump_target(); \ __asm__ volatile("mov x0, %0\n\t" \ "br %1\n\t" \ : \ - : "r"(cetRegContext), "r"(cetJumpAddress) \ + : "r"(ssRegContext), "r"(ssJumpAddress) \ : "x0"); \ } while (0) #endif @@ -255,16 +258,16 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except } #endif -// In CET enabled environment, we check return address stored in normal stack -// against return address stored in CET shadow stack, if the 2 addresses don't +// In shadow stack enabled environment, we check return address stored in normal +// stack against return address stored in shadow stack, if the 2 addresses don't // match, it means return address in normal stack has been corrupted, we return // _URC_FATAL_PHASE2_ERROR. #if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS) if (shadowStackTop != 0) { unw_word_t retInNormalStack; __unw_get_reg(cursor, UNW_REG_IP, &retInNormalStack); - unsigned long retInShadowStack = *( - unsigned long *)(shadowStackTop + __cet_ss_step_size * framesWalked); + unsigned long retInShadowStack = *(unsigned long *) + (shadowStackTop + __shadow_stack_step_size * framesWalked); if (retInNormalStack != retInShadowStack) return _URC_FATAL_PHASE2_ERROR; } diff --git a/libunwind/src/cet_unwind.h b/libunwind/src/shadow_stack_unwind.h similarity index 88% rename from libunwind/src/cet_unwind.h rename to libunwind/src/shadow_stack_unwind.h index 47d7616a7322c..8588ea01accd9 100644 --- a/libunwind/src/cet_unwind.h +++ b/libunwind/src/shadow_stack_unwind.h @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LIBUNWIND_CET_UNWIND_H -#define LIBUNWIND_CET_UNWIND_H +#ifndef LIBUNWIND_SHADOW_STACK_UNWIND_H +#define LIBUNWIND_SHADOW_STACK_UNWIND_H #include "libunwind.h" @@ -21,7 +21,7 @@ #include <cet.h> #include <immintrin.h> -#define _LIBUNWIND_POP_CET_SSP(x) \ +#define _LIBUNWIND_POP_SS_SSP(x) \ do { \ unsigned long ssp = _get_ssp(); \ if (ssp != 0) { \ @@ -46,7 +46,7 @@ #define _LIBUNWIND_USE_GCS 1 #endif -#define _LIBUNWIND_POP_CET_SSP(x) \ +#define _LIBUNWIND_POP_SS_SSP(x) \ do { \ if (__chkfeat(_CHKFEAT_GCS)) { \ unsigned tmp = (x); \ @@ -57,7 +57,7 @@ #endif -extern void *__libunwind_cet_get_registers(unw_cursor_t *); -extern void *__libunwind_cet_get_jump_target(void); +extern void *__libunwind_ss_get_registers(unw_cursor_t *); +extern void *__libunwind_ss_get_jump_target(void); #endif >From fc752004030ea5a50cba64bb0f3b452e280be8cf Mon Sep 17 00:00:00 2001 From: Ming-Yi Lai <ming-yi....@mediatek.com> Date: Tue, 11 Feb 2025 12:01:22 +0800 Subject: [PATCH 2/3] fixup: format code --- libunwind/src/CMakeLists.txt | 2 +- libunwind/src/Registers.hpp | 2 +- libunwind/src/UnwindLevel1.c | 11 ++++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libunwind/src/CMakeLists.txt b/libunwind/src/CMakeLists.txt index 3bbbc70fde79b..d69013e5dace1 100644 --- a/libunwind/src/CMakeLists.txt +++ b/libunwind/src/CMakeLists.txt @@ -36,7 +36,6 @@ set(LIBUNWIND_HEADERS AddressSpace.hpp assembly.h CompactUnwinder.hpp - shadow_stack_unwind.h config.h dwarf2.h DwarfInstructions.hpp @@ -46,6 +45,7 @@ set(LIBUNWIND_HEADERS libunwind_ext.h Registers.hpp RWMutex.hpp + shadow_stack_unwind.h Unwind-EHABI.h UnwindCursor.hpp ../include/libunwind.h diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index df79f0439ae85..e0a9448ce0c00 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -15,9 +15,9 @@ #include <stdint.h> #include <string.h> -#include "shadow_stack_unwind.h" #include "config.h" #include "libunwind.h" +#include "shadow_stack_unwind.h" namespace libunwind { diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c index 2d471d5d65690..50bcab7cffee8 100644 --- a/libunwind/src/UnwindLevel1.c +++ b/libunwind/src/UnwindLevel1.c @@ -25,10 +25,10 @@ #include <stdio.h> #include <string.h> -#include "shadow_stack_unwind.h" #include "config.h" #include "libunwind.h" #include "libunwind_ext.h" +#include "shadow_stack_unwind.h" #include "unwind.h" #if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) && \ @@ -62,7 +62,7 @@ void *ssJumpAddress = __libunwind_ss_get_jump_target(); \ __asm__ volatile("push %%edi\n\t" \ "sub $4, %%esp\n\t" \ - "jmp *%%edx\n\t" :: "D"(ssRegContext), \ + "jmp *%%edx\n\t" ::"D"(ssRegContext), \ "d"(ssJumpAddress)); \ } while (0) #elif defined(_LIBUNWIND_TARGET_X86_64) @@ -72,7 +72,7 @@ _LIBUNWIND_POP_SS_SSP((fn)); \ void *ssRegContext = __libunwind_ss_get_registers((cursor)); \ void *ssJumpAddress = __libunwind_ss_get_jump_target(); \ - __asm__ volatile("jmpq *%%rdx\n\t" :: "D"(ssRegContext), \ + __asm__ volatile("jmpq *%%rdx\n\t" ::"D"(ssRegContext), \ "d"(ssJumpAddress)); \ } while (0) #elif defined(_LIBUNWIND_TARGET_AARCH64) @@ -266,8 +266,9 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except if (shadowStackTop != 0) { unw_word_t retInNormalStack; __unw_get_reg(cursor, UNW_REG_IP, &retInNormalStack); - unsigned long retInShadowStack = *(unsigned long *) - (shadowStackTop + __shadow_stack_step_size * framesWalked); + unsigned long retInShadowStack = + *(unsigned long *)(shadowStackTop + + __shadow_stack_step_size * framesWalked); if (retInNormalStack != retInShadowStack) return _URC_FATAL_PHASE2_ERROR; } >From c8e5a5bb1a60b6b91b9c64b85b819e683d43fc81 Mon Sep 17 00:00:00 2001 From: Ming-Yi Lai <ming-yi....@mediatek.com> Date: Thu, 13 Feb 2025 10:35:52 +0800 Subject: [PATCH 3/3] fixup: Use "shstk" instead of "ss" as the new name --- libunwind/src/Registers.hpp | 6 ++--- libunwind/src/UnwindCursor.hpp | 2 +- libunwind/src/UnwindLevel1.c | 39 ++++++++++++++--------------- libunwind/src/shadow_stack_unwind.h | 8 +++--- 4 files changed, 27 insertions(+), 28 deletions(-) diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp index e0a9448ce0c00..452f46a0d56ea 100644 --- a/libunwind/src/Registers.hpp +++ b/libunwind/src/Registers.hpp @@ -48,7 +48,7 @@ class _LIBUNWIND_HIDDEN Registers_x86; extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *); #if defined(_LIBUNWIND_USE_CET) -extern "C" void *__libunwind_ss_get_jump_target() { +extern "C" void *__libunwind_shstk_get_jump_target() { return reinterpret_cast<void *>(&__libunwind_Registers_x86_jumpto); } #endif @@ -268,7 +268,7 @@ class _LIBUNWIND_HIDDEN Registers_x86_64; extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *); #if defined(_LIBUNWIND_USE_CET) -extern "C" void *__libunwind_ss_get_jump_target() { +extern "C" void *__libunwind_shstk_get_jump_target() { return reinterpret_cast<void *>(&__libunwind_Registers_x86_64_jumpto); } #endif @@ -1817,7 +1817,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64; extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *); #if defined(_LIBUNWIND_USE_GCS) -extern "C" void *__libunwind_ss_get_jump_target() { +extern "C" void *__libunwind_shstk_get_jump_target() { return reinterpret_cast<void *>(&__libunwind_Registers_arm64_jumpto); } #endif diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp index 5cb04b1f76820..ca9927edc9990 100644 --- a/libunwind/src/UnwindCursor.hpp +++ b/libunwind/src/UnwindCursor.hpp @@ -3122,7 +3122,7 @@ bool UnwindCursor<A, R>::isReadableAddr(const pint_t addr) const { #endif #if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS) -extern "C" void *__libunwind_ss_get_registers(unw_cursor_t *cursor) { +extern "C" void *__libunwind_shstk_get_registers(unw_cursor_t *cursor) { AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; return co->get_registers(); } diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c index 50bcab7cffee8..a258a832a9c31 100644 --- a/libunwind/src/UnwindLevel1.c +++ b/libunwind/src/UnwindLevel1.c @@ -42,7 +42,7 @@ // target is not tempered with. When unwinding, we're skipping the normal return // procedure for multiple frames and thus need to pop the return addresses of // the skipped frames from shadow stack to avoid triggering an exception (using -// `_LIBUNWIND_POP_SS_SSP()`). Also, some architectures, like the x86-family +// `_LIBUNWIND_POP_SHSTK_SSP()`). Also, some architectures, like the x86-family // CET, push the return adddresses onto shadow stack with common call // instructions, so for these architectures, normal function calls should be // avoided when invoking the `jumpto()` function. To do this, we use inline @@ -54,38 +54,38 @@ __unw_resume((cursor)); \ } while (0) #elif defined(_LIBUNWIND_TARGET_I386) -#define __shadow_stack_step_size (4) +#define __shstk_step_size (4) #define __unw_phase2_resume(cursor, fn) \ do { \ - _LIBUNWIND_POP_SS_SSP((fn)); \ - void *ssRegContext = __libunwind_ss_get_registers((cursor)); \ - void *ssJumpAddress = __libunwind_ss_get_jump_target(); \ + _LIBUNWIND_POP_SHSTK_SSP((fn)); \ + void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \ + void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \ __asm__ volatile("push %%edi\n\t" \ "sub $4, %%esp\n\t" \ - "jmp *%%edx\n\t" ::"D"(ssRegContext), \ - "d"(ssJumpAddress)); \ + "jmp *%%edx\n\t" ::"D"(shstkRegContext), \ + "d"(shstkJumpAddress)); \ } while (0) #elif defined(_LIBUNWIND_TARGET_X86_64) -#define __shadow_stack_step_size (8) +#define __shstk_step_size (8) #define __unw_phase2_resume(cursor, fn) \ do { \ - _LIBUNWIND_POP_SS_SSP((fn)); \ - void *ssRegContext = __libunwind_ss_get_registers((cursor)); \ - void *ssJumpAddress = __libunwind_ss_get_jump_target(); \ - __asm__ volatile("jmpq *%%rdx\n\t" ::"D"(ssRegContext), \ - "d"(ssJumpAddress)); \ + _LIBUNWIND_POP_SHSTK_SSP((fn)); \ + void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \ + void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \ + __asm__ volatile("jmpq *%%rdx\n\t" ::"D"(shstkRegContext), \ + "d"(shstkJumpAddress)); \ } while (0) #elif defined(_LIBUNWIND_TARGET_AARCH64) -#define __shadow_stack_step_size (8) +#define __shstk_step_size (8) #define __unw_phase2_resume(cursor, fn) \ do { \ - _LIBUNWIND_POP_SS_SSP((fn)); \ - void *ssRegContext = __libunwind_ss_get_registers((cursor)); \ - void *ssJumpAddress = __libunwind_ss_get_jump_target(); \ + _LIBUNWIND_POP_SHSTK_SSP((fn)); \ + void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \ + void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \ __asm__ volatile("mov x0, %0\n\t" \ "br %1\n\t" \ : \ - : "r"(ssRegContext), "r"(ssJumpAddress) \ + : "r"(shstkRegContext), "r"(shstkJumpAddress) \ : "x0"); \ } while (0) #endif @@ -267,8 +267,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except unw_word_t retInNormalStack; __unw_get_reg(cursor, UNW_REG_IP, &retInNormalStack); unsigned long retInShadowStack = - *(unsigned long *)(shadowStackTop + - __shadow_stack_step_size * framesWalked); + *(unsigned long *)(shadowStackTop + __shstk_step_size * framesWalked); if (retInNormalStack != retInShadowStack) return _URC_FATAL_PHASE2_ERROR; } diff --git a/libunwind/src/shadow_stack_unwind.h b/libunwind/src/shadow_stack_unwind.h index 8588ea01accd9..1f229d8317116 100644 --- a/libunwind/src/shadow_stack_unwind.h +++ b/libunwind/src/shadow_stack_unwind.h @@ -21,7 +21,7 @@ #include <cet.h> #include <immintrin.h> -#define _LIBUNWIND_POP_SS_SSP(x) \ +#define _LIBUNWIND_POP_SHSTK_SSP(x) \ do { \ unsigned long ssp = _get_ssp(); \ if (ssp != 0) { \ @@ -46,7 +46,7 @@ #define _LIBUNWIND_USE_GCS 1 #endif -#define _LIBUNWIND_POP_SS_SSP(x) \ +#define _LIBUNWIND_POP_SHSTK_SSP(x) \ do { \ if (__chkfeat(_CHKFEAT_GCS)) { \ unsigned tmp = (x); \ @@ -57,7 +57,7 @@ #endif -extern void *__libunwind_ss_get_registers(unw_cursor_t *); -extern void *__libunwind_ss_get_jump_target(void); +extern void *__libunwind_shstk_get_registers(unw_cursor_t *); +extern void *__libunwind_shstk_get_jump_target(void); #endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits