#define HB_BITS 15
#define HB_SIZE (1 << HB_BITS)
+/* Return lengths of high (starting at param->ho) and low (starting at 0) fragments of the circular history buffer. */
+static inline void get_history_lengths(struct dfltcc_param_v0 *param, size_t *hl_high, size_t *hl_low) {
+ *hl_high = MIN(param->hl, HB_SIZE - param->ho);
+ *hl_low = param->hl - *hl_high;
+}
+
+/* Notify instrumentation about an upcoming read/write access to the circular history buffer. */
+static inline void instrument_read_write_hist(struct dfltcc_param_v0 *param, void *hist) {
+ size_t hl_high, hl_low;
+
+ get_history_lengths(param, &hl_high, &hl_low);
+ instrument_read_write(hist + param->ho, hl_high);
+ instrument_read_write(hist, hl_low);
+}
+
+/* Notify MSan about a completed write to the circular history buffer. */
+static inline void msan_unpoison_hist(struct dfltcc_param_v0 *param, void *hist) {
+ size_t hl_high, hl_low;
+
+ get_history_lengths(param, &hl_high, &hl_low);
+ __msan_unpoison(hist + param->ho, hl_high);
+ __msan_unpoison(hist, hl_low);
+}
+
static inline dfltcc_cc dfltcc(int fn, void *param,
unsigned char **op1, size_t *len1,
z_const unsigned char **op2, size_t *len2, void *hist) {
size_t t3 = len1 ? *len1 : 0;
z_const unsigned char *t4 = op2 ? *op2 : NULL;
size_t t5 = len2 ? *len2 : 0;
- Z_REGISTER int r0 __asm__("r0") = fn;
- Z_REGISTER void *r1 __asm__("r1") = param;
- Z_REGISTER unsigned char *r2 __asm__("r2") = t2;
- Z_REGISTER size_t r3 __asm__("r3") = t3;
- Z_REGISTER z_const unsigned char *r4 __asm__("r4") = t4;
- Z_REGISTER size_t r5 __asm__("r5") = t5;
+ Z_REGISTER int r0 __asm__("r0");
+ Z_REGISTER void *r1 __asm__("r1");
+ Z_REGISTER unsigned char *r2 __asm__("r2");
+ Z_REGISTER size_t r3 __asm__("r3");
+ Z_REGISTER z_const unsigned char *r4 __asm__("r4");
+ Z_REGISTER size_t r5 __asm__("r5");
int cc;
+ /* Insert pre-instrumentation for DFLTCC. */
+ switch (fn & DFLTCC_FN_MASK) {
+ case DFLTCC_QAF:
+ instrument_write(param, DFLTCC_SIZEOF_QAF);
+ break;
+ case DFLTCC_GDHT:
+ instrument_read_write(param, DFLTCC_SIZEOF_GDHT_V0);
+ instrument_read(t4, t5);
+ break;
+ case DFLTCC_CMPR:
+ case DFLTCC_XPND:
+ instrument_read_write(param, DFLTCC_SIZEOF_CMPR_XPND_V0);
+ instrument_read(t4, t5);
+ instrument_write(t2, t3);
+ instrument_read_write_hist(param, hist);
+ break;
+ }
+
+ r0 = fn; r1 = param; r2 = t2; r3 = t3; r4 = t4; r5 = t5;
__asm__ volatile(
#ifdef HAVE_SYS_SDT_H
STAP_PROBE_ASM(zlib, dfltcc_entry, STAP_PROBE_ASM_TEMPLATE(5))
: "cc", "memory");
t2 = r2; t3 = r3; t4 = r4; t5 = r5;
+ /* Insert post-instrumentation for DFLTCC. */
switch (fn & DFLTCC_FN_MASK) {
case DFLTCC_QAF:
__msan_unpoison(param, DFLTCC_SIZEOF_QAF);
case DFLTCC_CMPR:
__msan_unpoison(param, DFLTCC_SIZEOF_CMPR_XPND_V0);
__msan_unpoison(orig_t2, t2 - orig_t2 + (((struct dfltcc_param_v0 *)param)->sbb == 0 ? 0 : 1));
+ msan_unpoison_hist(param, hist);
break;
case DFLTCC_XPND:
__msan_unpoison(param, DFLTCC_SIZEOF_CMPR_XPND_V0);
__msan_unpoison(orig_t2, t2 - orig_t2);
+ msan_unpoison_hist(param, hist);
break;
}
static inline void get_history(struct dfltcc_param_v0 *param, const unsigned char *history,
unsigned char *buf) {
- if (param->ho + param->hl <= HB_SIZE)
- /* Circular history buffer does not wrap - copy one chunk */
- memcpy(buf, history + param->ho, param->hl);
- else {
- /* Circular history buffer wraps - copy two chunks */
- memcpy(buf, history + param->ho, HB_SIZE - param->ho);
- memcpy(buf + HB_SIZE - param->ho, history, param->ho + param->hl - HB_SIZE);
- }
+ size_t hl_high, hl_low;
+
+ get_history_lengths(param, &hl_high, &hl_low);
+ memcpy(buf, history + param->ho, hl_high);
+ memcpy(buf + hl_high, history, hl_low);
}
# endif
#endif
+#if defined(__has_feature)
+# if __has_feature(address_sanitizer)
+# define Z_ADDRESS_SANITIZER 1
+# endif
+#elif defined(__SANITIZE_ADDRESS__)
+# define Z_ADDRESS_SANITIZER 1
+#endif
+
+/*
+ * __asan_loadN() and __asan_storeN() calls are inserted by compilers in order to check memory accesses.
+ * They can be called manually too, with the following caveats:
+ * gcc says: "warning: implicit declaration of function ‘...’"
+ * g++ says: "error: new declaration ‘...’ ambiguates built-in declaration ‘...’"
+ * Accommodate both.
+ */
+#ifdef Z_ADDRESS_SANITIZER
+#ifndef __cplusplus
+void __asan_loadN(void *, long);
+void __asan_storeN(void *, long);
+#endif
+#else
+# define __asan_loadN(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0)
+# define __asan_storeN(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0)
+#endif
+
#if defined(__has_feature)
# if __has_feature(memory_sanitizer)
# define Z_MEMORY_SANITIZER 1
#endif
#ifndef Z_MEMORY_SANITIZER
+# define __msan_check_mem_is_initialized(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0)
# define __msan_unpoison(a, size) do { Z_UNUSED(a); Z_UNUSED(size); } while (0)
#endif
+/* Notify sanitizer runtime about an upcoming read access. */
+#define instrument_read(a, size) do { \
+ void *__a = (void *)(a); \
+ long __size = size; \
+ __asan_loadN(__a, __size); \
+ __msan_check_mem_is_initialized(__a, __size); \
+} while (0)
+
+/* Notify sanitizer runtime about an upcoming write access. */
+#define instrument_write(a, size) do { \
+ void *__a = (void *)(a); \
+ long __size = size; \
+ __asan_storeN(__a, __size); \
+} while (0)
+
+/* Notify sanitizer runtime about an upcoming read/write access. */
+#define instrument_read_write(a, size) do { \
+ void *__a = (void *)(a); \
+ long __size = size; \
+ __asan_storeN(__a, __size); \
+ __msan_check_mem_is_initialized(__a, __size); \
+} while (0)
+
#endif