public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
From: Bill Tsui <b10902118@ntu.edu.tw>
To: Will Deacon <will@kernel.org>
Cc: oleg@redhat.com, linux@armlinux.org.uk, catalin.marinas@arm.com,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 1/3] arm64: ptrace: fix hw_break_set() by setting addr and ctrl together
Date: Wed, 17 Sep 2025 22:23:49 +0800	[thread overview]
Message-ID: <0fd573cc044584f00976c410955ed486@ntu.edu.tw> (raw)
In-Reply-To: <dcb568c3dd5feb15890fa75e988e33bb@ntu.edu.tw>

The following can reproduce the error for `arm64 compat` watchpoints
(breakpoints follow the same logic). I realized that testing my patch
can take time to set up from scratch, hoping this can facilitate the
review process.

There are three parts:
1. watch_unaligned.c
2. tracee.c
3. compile & run

Basically, watch_unaligned runs tracee and set 1-byte watchpoints on it.


1. watch_unaligned.c

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/ptrace.h>
#include <asm/ptrace.h>
#include <sys/uio.h>
#include <elf.h>
#include <sys/uio.h>
#include <asm/ptrace.h>

#define MAX_WATCHPOINTS 4

#define AARCH64_BREAKPOINT_EL0 2

#define ENABLE 1

typedef enum {
     arm_hwbp_break = 0,
     arm_hwbp_load = 1,
     arm_hwbp_store = 2,
     arm_hwbp_access = 3
} arm_hwbp_type;

void error_detach_close(pid_t pid, FILE* pipe, const char* msg) {
     perror(msg);
     ptrace(PTRACE_DETACH, pid, NULL, NULL);
     pclose(pipe);
}

void watch_1byte(int pid, uint32_t addr) {
     // Set hardware watchpoint on ARM64
     // Use PTRACE_SETREGSET with NT_ARM_HW_WATCH for watchpoints
     printf("Setting watchpoint at address 0x%x\n", addr);
     struct user_hwdebug_state watch;
     memset(&watch, 0, sizeof(watch));
     watch.dbg_regs[0].addr = addr;
     uint32_t size = 1;
     uint32_t byte_mask = (1u << size) - 1u;
     uint32_t type = arm_hwbp_access;
     uint32_t priv = AARCH64_BREAKPOINT_EL0;
     watch.dbg_regs[0].ctrl =
         (byte_mask << 5) | (type << 3) | (priv << 1) | ENABLE;

     struct iovec ioVec;
     memset(&ioVec, 0, sizeof(ioVec));
     ioVec.iov_base = &watch;
     // According to lldb. Otherwise dbg_regs[16] will cause error
     ioVec.iov_len = sizeof(watch.dbg_info) + sizeof(watch.pad) +
                     (sizeof(watch.dbg_regs[0]) * MAX_WATCHPOINTS);

     if (ptrace(PTRACE_SETREGSET, pid, NT_ARM_HW_WATCH, &ioVec) == -1) {
         perror("PTRACE_SETREGSET");
     } else {
         printf("Watchpoint at address 0x%x set successfully\n", addr);
     }
     printf("---\n");
}

FILE* run_tracee(pid_t *pid, uint32_t *addr) {
     // run tracee and get pid & addr
     FILE *pipe = popen("./tracee", "r");
     if (!pipe) {
         perror("popen failed");
         return NULL;
     }

     char line[64];
     if (fgets(line, sizeof(line), pipe) == NULL) {
         perror("read pid failed");
     }
     *pid = atoi(line);

     if (fgets(line, sizeof(line), pipe) == NULL) {
         perror("read addr failed");
     }
     *addr = strtoul(line, NULL, 0);

     return pipe;
}

int main() {
     pid_t pid;
     uint32_t addr;

     FILE *pipe = run_tracee(&pid, &addr);
     if (!pipe) {
         return 1;
     }

     printf("Attaching to PID %d\n", pid);
     if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) {
         error_detach_close(pid, pipe, "ptrace(ATTACH)");
         return 1;
     }
     printf("Attached\n\n");

     int status = 0;
     if (waitpid(pid, &status, 0) == -1) {
         error_detach_close(pid, pipe, "waitpid");
         return 1;
     }

     // The TEST

     // watch non-4-byte aligned. (Fail)
     watch_1byte(pid, addr);
     // watch any 4-byte aligned. (Success)
     watch_1byte(pid, 0);
     // watch non-4-byte aligned again. (Success)
     // because bp_len was previously set to 2 successfully
     watch_1byte(pid, addr);

     // continue and let it trigger, proving functionality
     if (ptrace(PTRACE_CONT, pid, NULL, NULL) == -1) {
         error_detach_close(pid, pipe,"ptrace(CONT)");
         return 1;
     }
     if (waitpid(pid, &status, 0) == -1) {
         error_detach_close(pid, pipe, "waitpid (after CONT)");
         pclose(pipe);
         return 1;
     }
     if (WIFSTOPPED(status)) {
         printf("Watchpoint triggered, signal: %d\n", WSTOPSIG(status));
         ptrace(PTRACE_CONT, pid, NULL, NULL);
         ptrace(PTRACE_DETACH, pid, NULL, NULL);
     }
     pclose(pipe);
     return 0;
}


2. tracee.c

#include <stdio.h>
#include <unistd.h>
#include <stdint.h>

int main() {
     volatile int a = 42;
     printf("%d\n%p\n", getpid(), (void*)((uintptr_t)&a + 1));
     fflush(stdout);
     while (1) {
         a += 1;
     }

     return 0;
}


3. compile & run

# 64-bit tracer
aarch64-linux-gnu-gcc watch_unaligned.c -o watch_unaligned

# 32-bit tracee
arm-linux-gnueabi-gcc tracee.c -o tracee

# run
./watch_unaligned

output:

     Attaching to PID 325
     Attached

     Setting watchpoint at address 0xffacca39
     PTRACE_SETREGSET: Invalid argument
     ---
     Setting watchpoint at address 0x0
     Watchpoint at address 0x0 set successfully
     ---
     Setting watchpoint at address 0xffacca39
     Watchpoint at address 0xffacca39 set successfully
     ---
     Watchpoint triggered, signal: 5

Summary: the first watchpoint failed but should be supported since it 
was
successfully set and triggered just after addr 0x0 with length 1.

Thanks,
Bill


  reply	other threads:[~2025-09-17 14:24 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-08-24 12:43 [PATCH 0/3] ARM/arm64: ptrace: fix unaligned hardware breakpoint validation for 32bit b10902118
2025-08-24 12:43 ` [PATCH 1/3] arm64: ptrace: fix hw_break_set() by setting addr and ctrl together b10902118
2025-08-24 12:43 ` [PATCH 2/3] arm64: ptrace: minimize default bp_len for hw breakpoints to pass check b10902118
2025-08-24 12:43 ` [PATCH 3/3] ARM: " b10902118
2025-08-26 19:37 ` [PATCH 0/3] ARM/arm64: ptrace: fix unaligned hardware breakpoint validation for 32bit Catalin Marinas
2025-08-27  1:41 ` [PATCH v2 " Bill Tsui
2025-08-27  1:41   ` [PATCH v2 1/3] arm64: ptrace: fix hw_break_set() by setting addr and ctrl together Bill Tsui
2025-09-08 15:14     ` Will Deacon
2025-09-09  1:50       ` b10902118
2025-09-09  1:57       ` Bill Tsui
2025-09-17 14:23         ` Bill Tsui [this message]
2025-08-27  1:41   ` [PATCH v2 2/3] arm64: ptrace: minimize default bp_len for hw breakpoints to pass check Bill Tsui
2025-08-27  1:41   ` [PATCH v2 3/3] ARM: " Bill Tsui
2025-10-16 15:44   ` [PATCH v3 0/1] arm64: ptrace: fix hw_break_set() to set addr and ctrl together Bill Tsui
2025-10-16 15:44     ` [PATCH v3 1/1] " Bill Tsui
2025-10-18  8:24       ` kernel test robot
2025-10-18 13:37     ` [PATCH v4 0/1] " Bill Tsui
2025-10-18 13:37       ` [PATCH v4 1/1] " Bill Tsui
2025-11-14 16:14         ` Will Deacon
2025-11-15  3:44           ` Bill Tsui

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0fd573cc044584f00976c410955ed486@ntu.edu.tw \
    --to=b10902118@ntu.edu.tw \
    --cc=catalin.marinas@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=oleg@redhat.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox