A GDB stop leaves the other guest threads running instead of stopping them (all-stop)
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 52/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- c
- Lĩnh vực
- operating-systems
Hướng nghiên cứu
Start by reading gdb_stub_handle_stop in src/debug/gdbstub.c and the canceled-exit handler in src/syscall/proc.c, then trace how stop requests are cleared on resume. Use the supplied two-thread reproducer and raw RSP client to check whether the counter stays unchanged after the T05 stop reply; done means sibling threads remain stopped until GDB resumes.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
What happens
When one thread stops at a breakpoint under --gdb, the other guest threads keep running guest code while GDB inspects and writes state. GDB's all-stop mode, which the stub's comments describe ("Stop all other vCPUs (all-stop mode)"), expects every thread to be stopped until the next resume.
Evidence
On upstream main a20dfab, the probe below, a guest with one thread spinning on counter++ while the main thread calls bp_here(), driven by the raw RSP client below:
Z0: OK
stop reply: T05
counter while stopped: 232115109 -> 809825692 (changed)
The counter grew by 577,710,583 in the 0.5 s between two m reads after the T05 stop reply. No Linux comparison: the qemu reference VM has no gdbserver.
Cause
Checked by reading. In gdb_stub_handle_stop (src/debug/gdbstub.c) the first thread to stop sets all_stopped, clears stop_requested, and only then calls thread_interrupt_all. thread_interrupt_all only kicks every vCPU out of hv_vcpu_run. A kicked sibling's canceled-exit handler in src/syscall/proc.c enters the GDB stop only when gdb_stub_stop_requested() returns true, and that function reads stop_requested alone, which is already 0, so the sibling resumes guest code. Nothing else in the run loop checks all_stopped.
Reproduce
#include <pthread.h>
#include <stdint.h>
#include <unistd.h>
volatile uint64_t counter;
__attribute__((noinline)) void bp_here(void) { __asm__ volatile("" ::: "memory"); }
static void *spin(void *arg)
{
(void) arg;
for (;;)
counter++;
return NULL;
}
int main(void)
{
pthread_t t;
pthread_create(&t, NULL, spin, NULL);
usleep(200 * 1000);
bp_here();
return 0;
}
Build it static, start it with build/elfuse --gdb 23947 --gdb-stop-on-entry ./gdb_allstop, and run this client with the addresses of bp_here and counter from nm:
import socket, sys, time
port, bp, ctr = int(sys.argv[1]), int(sys.argv[2], 16), int(sys.argv[3], 16)
s = None
for _ in range(100):
try:
s = socket.create_connection(("127.0.0.1", port), timeout=10)
break
except OSError:
time.sleep(0.1)
buf = b""
def pkt(data):
s.sendall(("$%s#%02x" % (data, sum(data.encode()) & 0xFF)).encode())
def reply():
global buf
while True:
i = buf.find(b"$"); j = buf.find(b"#", i)
if i >= 0 and j >= 0 and len(buf) >= j + 3:
body = buf[i + 1:j].decode(); buf = buf[j + 3:]
s.sendall(b"+")
return body
buf += s.recv(4096)
def cmd(data):
pkt(data)
return reply()
cmd("?")
print("Z0:", cmd("Z0,%x,4" % bp))
print("stop reply:", cmd("c")[:3])
read = lambda: int.from_bytes(bytes.fromhex(cmd("m%x,8" % ctr)), "little")
a = read(); time.sleep(0.5); b = read()
print("counter while stopped: %d -> %d (%s)" % (a, b, "changed" if b != a else "unchanged"))
pkt("k")
Possible fix
Keep the stop request raised until GDB resumes: clear stop_requested in the resume paths (c, s, vCont, detach) rather than in gdb_stub_handle_stop, or have gdb_stub_stop_requested also return true while all_stopped is set. Kicked siblings then park in gdb_stub_handle_stop until the resume.
Origin
Follow-up from #525.
- Ngôn ngữ chính
- C
- Star
- 282
- Fork
- 32
- Merge trung bình
- 1 ngày 12 giờ
- Pull request đã merge (30 ngày)
- 17
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của sysprog21/elfuse
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 80/100
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 86/100
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của sysprog21/elfuse
Issue tương tự
-
polish
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
ChupathingyCE/chupathingyce#1366 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
slice track:dev
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 64/100
Life-Framework/Life-Framework#1831 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 80/100
-
bug intrinsic low priority wrong result
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Maintainer thường phản hồi trong vòng 1 ngày