Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function Hook to CInputManager::getMouseCoordsInternal only works in debug mode. #8845

Closed
1 task done
raybbian opened this issue Dec 25, 2024 · 25 comments
Closed
1 task done
Labels
bug Something isn't working

Comments

@raybbian
Copy link
Contributor

raybbian commented Dec 25, 2024

Already reported ? *

  • I have searched the existing open and closed issues.

Regression?

No

System Info and Version

tmp.txt

Description

I'm developing a plugin that wants to hook into getMouseCoordsInternal to change the position of the mouse when some conditions are met.

On a nested debug build of Hyprland, my plugin is able to hook just fine. However, on nested release builds of Hyprland, the API reports a successful hook, but the hook is not called. On non-nested release Hyprland, any attempts to call the original function through m_pOriginal of CFunctionHook causes a segfault in the plugin, which unloads the plugin.

Here is how I am hooking the functions:

static void initFunctions() {
    static auto FNS =
        HyprlandAPI::findFunctionsByName(PHANDLE, "renderWorkspace");
    if (FNS.empty()) {
        failNotification("No fns for hook renderWorkspace!");
        throw std::runtime_error(
            "[Hyprtasking] No fns for hook renderWorkspace");
    }
    g_pRenderWorkspaceHook = HyprlandAPI::createFunctionHook(
        PHANDLE, FNS[0].address, (void *)hkRenderWorkspace);

    FNS = HyprlandAPI::findFunctionsByName(PHANDLE, "getMouseCoordsInternal");
    if (FNS.empty()) {
        failNotification("No fns for hook getMouseCoordsInternal");
        throw std::runtime_error(
            "[Hyprtasking] No fns for hook getMouseCoordsInternal");
    }
    g_pGetMouseCoordsInternalHook = HyprlandAPI::createFunctionHook(
        PHANDLE, FNS[0].address, (void *)hkGetMouseCoordsInternal);

    bool success = g_pRenderWorkspaceHook->hook();
    success = success && g_pGetMouseCoordsInternalHook->hook();
    if (!success) {
        failNotification("Failed initializing hooks");
        throw std::runtime_error("[Hyprtasking] Failed initializing hooks");
    }
}

The function that should execute: (No logs are printed in release builds, while they are printed in Debug builds)

static Vector2D hkGetMouseCoordsInternal(void *thisptr) {
    Debug::log(LOG, std::format("[Hyprtasking] getMouseCoords hook called"));
    const Vector2D oMousePos =
        ((tGetMouseCoordsInternal)(g_pGetMouseCoordsInternalHook->m_pOriginal))(
            thisptr);
    const PHLMONITOR pMonitor = g_pCompositor->getMonitorFromVector(oMousePos);
    const auto view = getViewForMonitor(pMonitor);

    if (pMonitor == nullptr || view == nullptr || !view->isActive())
        return oMousePos;

    const Vector2D newPos = view->mouseCoordsWorkspaceRelative(oMousePos);
    Debug::log(
        LOG, std::format(
                 "[Hyprtasking] mouse coords hooked from ({}, {}) to ({}, {})",
                 oMousePos.x, oMousePos.y, newPos.x, newPos.y));
    return newPos;
}

What causes the segfault in non-nested release:

    const Vector2D mousePos =
        ((tGetMouseCoordsInternal)(g_pGetMouseCoordsInternalHook->m_pOriginal))(
            g_pInputManager.get());

How to reproduce

  1. Create a plugin that hooks getMouseCoordsInternal (Can attempt with https://github.com/raybbian/hyprtasking)
  2. Load the plugin on release build Hyprland
  3. Call the original function (will happen on mouse move after dispatching hyprtasking:toggle)
    a. Also note that hook is not called
  4. Segfault

Crash reports, logs, images, videos

Nested release:
https://github.com/user-attachments/assets/0faed1ff-46de-41ee-85e3-287863feafef

Nested debug:
https://github.com/user-attachments/assets/33789962-d09d-4295-b9d5-68a7c0391bf9

Release:
https://github.com/user-attachments/assets/7fb4330b-dea3-4147-9762-57b8f822dba4

@raybbian raybbian added the bug Something isn't working label Dec 25, 2024
@raybbian
Copy link
Contributor Author

raybbian commented Dec 25, 2024

Function getting inlined maybe? Happy to provide logs, additional info

@vaxerski
Copy link
Member

vaxerski commented Dec 25, 2024

can you install the hook on a release version, attach gdb to the running hyprland (you can do it via ssh, because it will freeze hyprland) sudo gdb attach $(pidof Hyprland) and run disassemble _ZN13CInputManager22getMouseCoordsInternalEv?

@raybbian
Copy link
Contributor Author

raybbian commented Dec 25, 2024

yeah, one sec

EDIT:
Non-nested release:

(gdb) disassemble _ZN13CInputManager22getMouseCoordsInternalEv
Dump of assembler code for function _ZN13CInputManager22getMouseCoordsInternalEv:
   0x0000573823a8f3e0 <+0>:     endbr64
   0x0000573823a8f3e4 <+4>:     lea    0x45552d(%rip),%rdx        # 0x573823ee4918 <g_pPointerManager>
   0x0000573823a8f3eb <+11>:    mov    %rdi,%rax
   0x0000573823a8f3ee <+14>:    mov    (%rdx),%rdx
   0x0000573823a8f3f1 <+17>:    movdqu 0xc0(%rdx),%xmm0
   0x0000573823a8f3f9 <+25>:    movups %xmm0,(%rdi)
   0x0000573823a8f3fc <+28>:    ret
End of assembler dump.

Nested release:

(gdb) disassemble _ZN13CInputManager22getMouseCoordsInternalEv
Dump of assembler code for function _ZN13CInputManager22getMouseCoordsInternalEv:
   0x0000640dad487dc0 <+0>:    push   %rbx
   0x0000640dad487dc1 <+1>:    sub    $0x10,%rsp
   0x0000640dad487dc5 <+5>:    mov    0x4b89ec(%rip),%rsi        # 0x640dad9407b8 <g_pPointerManager>
   0x0000640dad487dcc <+12>:    mov    %fs:0x28,%rbx
   0x0000640dad487dd5 <+21>:    mov    %rbx,0x8(%rsp)
   0x0000640dad487dda <+26>:    mov    %rdi,%rbx
   0x0000640dad487ddd <+29>:    call   0x640dad44bd30 <_ZN15CPointerManager8positionEv>
   0x0000640dad487de2 <+34>:    mov    0x8(%rsp),%rax
   0x0000640dad487de7 <+39>:    sub    %fs:0x28,%rax
   0x0000640dad487df0 <+48>:    jne    0x640dad487dfb <_ZN13CInputManager22getMouseCoordsInternalEv+59>
   0x0000640dad487df2 <+50>:    add    $0x10,%rsp
   0x0000640dad487df6 <+54>:    mov    %rbx,%rax
   0x0000640dad487df9 <+57>:    pop    %rbx
   0x0000640dad487dfa <+58>:    ret
   0x0000640dad487dfb <+59>:    call   0x640dad1d0980 <__stack_chk_fail@plt>
End of assembler dump.

Nested debug:

(gdb) disassemble _ZN13CInputManager22getMouseCoordsInternalEv
Dump of assembler code for function _ZN13CInputManager22getMouseCoordsInternalEv:
   0x0000641327fd1210 <+0>:	push   %rbp
   0x0000641327fd1211 <+1>:	mov    %rsp,%rbp
   0x0000641327fd1214 <+4>:	sub    $0x20,%rsp
   0x0000641327fd1218 <+8>:	mov    %rdi,-0x18(%rbp)
   0x0000641327fd121c <+12>:	mov    %rsi,-0x20(%rbp)
   0x0000641327fd1220 <+16>:	mov    %fs:0x28,%rax
   0x0000641327fd1229 <+25>:	mov    %rax,-0x8(%rbp)
   0x0000641327fd122d <+29>:	xor    %eax,%eax
   0x0000641327fd122f <+31>:	lea    0xa3291a(%rip),%rax        # 0x641328a03b50 <g_pPointerManager>
   0x0000641327fd1236 <+38>:	mov    %rax,%rdi
   0x0000641327fd1239 <+41>:	call   0x641327ceb20c <_ZNKSt10unique_ptrI15CPointerManagerSt14default_deleteIS0_EEptEv>
   0x0000641327fd123e <+46>:	mov    %rax,%rdx
   0x0000641327fd1241 <+49>:	mov    -0x18(%rbp),%rax
   0x0000641327fd1245 <+53>:	mov    %rdx,%rsi
   0x0000641327fd1248 <+56>:	mov    %rax,%rdi
   0x0000641327fd124b <+59>:	call   0x641327f4fa2c <_ZN15CPointerManager8positionEv>
   0x0000641327fd1250 <+64>:	mov    -0x8(%rbp),%rax
   0x0000641327fd1254 <+68>:	sub    %fs:0x28,%rax
   0x0000641327fd125d <+77>:	je     0x641327fd1264 <_ZN13CInputManager22getMouseCoordsInternalEv+84>
   0x0000641327fd125f <+79>:	call   0x641327caa530 <__stack_chk_fail@plt>
   0x0000641327fd1264 <+84>:	mov    -0x18(%rbp),%rax
   0x0000641327fd1268 <+88>:	leave
   0x0000641327fd1269 <+89>:	ret
End of assembler dump.

@vaxerski
Copy link
Member

possible we tripped CFI. Try building hyprland with -fcf-protection=none and see if it gets rid of the endbr64

@raybbian
Copy link
Contributor Author

raybbian commented Dec 25, 2024

I should clarify: my "non-nested release" Hyprland is installed from pacman:

[rayb@rayb-linux build]$ which Hyprland
/usr/bin/Hyprland
[rayb@rayb-linux build]$ hyprland -v
Hyprland 0.46.2 built from branch  at commit 0bd541f2fd902dbfa04c3ea2ccf679395e316887  (version: bump to 0.46.2).
Date: Thu Dec 19 19:26:47 2024
Tag: v0.46.2, commits: 5566
built against:
 aquamarine 0.5.1
 hyprlang 0.6.0
 hyprutils 0.3.0
 hyprcursor 0.1.11
 hyprgraphics 0.1.1


flags set:
debug

Nested release hyprland is build from hyprland-git with the appropriate commit checked out:

[rayb@rayb-linux build]$ which ./Hyprland 
/home/rayb/Projects/hyprland-git/build/Hyprland
[rayb@rayb-linux build]$ ./Hyprland -v
Hyprland 0.46.2 built from branch  at commit 0bd541f2fd902dbfa04c3ea2ccf679395e316887 dirty (version: bump to 0.46.2).
Date: Thu Dec 19 14:26:47 2024
Tag: v0.46.2, commits: 5566
built against:
 aquamarine 0.5.1
 hyprlang 0.6.0
 hyprutils 0.2.6
 hyprcursor 0.1.10
 hyprgraphics 0.1.1


flags set:
debug

Compiling hyprland from the repository with -fcf-protection=none yields the same asm as previous:

(gdb) disassemble _ZN13CInputManager22getMouseCoordsInternalEv
Dump of assembler code for function _ZN13CInputManager22getMouseCoordsInternalEv:
   0x00005c72a7fc9dc0 <+0>:     push   %rbx
   0x00005c72a7fc9dc1 <+1>:     sub    $0x10,%rsp
   0x00005c72a7fc9dc5 <+5>:     mov    0x4b89ec(%rip),%rsi        # 0x5c72a84827b8 <g_pPointerManager>
   0x00005c72a7fc9dcc <+12>:    mov    %fs:0x28,%rbx
   0x00005c72a7fc9dd5 <+21>:    mov    %rbx,0x8(%rsp)
   0x00005c72a7fc9dda <+26>:    mov    %rdi,%rbx
   0x00005c72a7fc9ddd <+29>:    call   0x5c72a7f8dd30 <_ZN15CPointerManager8positionEv>
   0x00005c72a7fc9de2 <+34>:    mov    0x8(%rsp),%rax
   0x00005c72a7fc9de7 <+39>:    sub    %fs:0x28,%rax
   0x00005c72a7fc9df0 <+48>:    jne    0x5c72a7fc9dfb <_ZN13CInputManager22getMouseCoordsInternalEv+59>
   0x00005c72a7fc9df2 <+50>:    add    $0x10,%rsp
   0x00005c72a7fc9df6 <+54>:    mov    %rbx,%rax
   0x00005c72a7fc9df9 <+57>:    pop    %rbx
   0x00005c72a7fc9dfa <+58>:    ret
   0x00005c72a7fc9dfb <+59>:    call   0x5c72a7d12980 <__stack_chk_fail@plt>
End of assembler dump.

The PKGBUILD for Hyprland doesn't seem to add any additional flags - I am unsure how to recreate "nested release" Hyprland behavior/assembly.

EDIT: tried compiling with code from https://github.com/hyprwm/Hyprland/releases/download/v0.46.2/source-v0.46.2.tar.gz but also got "nested release" asm. Need to match dependency versions as well?

EDIT: yeah, I'm unable to reproduce the "non-nested release" asm.

@vaxerski
Copy link
Member

I assume without the endbr64 at the beginning, the hook works?

@raybbian
Copy link
Contributor Author

raybbian commented Dec 25, 2024

No - on "nested release" my hook is never called - as if the function wasn't hooked in the first place

@vaxerski
Copy link
Member

Can you show the disassembly of nested release (where it doesnt work) where you already loaded and applied your hook and it doesnt work?

@raybbian
Copy link
Contributor Author

(gdb) disassemble _ZN13CInputManager22getMouseCoordsInternalEv
Dump of assembler code for function _ZN13CInputManager22getMouseCoordsInternalEv:
   0x000058d991b07dc0 <+0>:	movabs $0x74a7582c7f8e,%rax
   0x000058d991b07dca <+10>:	jmp    *%rax
   0x000058d991b07dcc <+12>:	pop    %rax
   0x000058d991b07dcd <+13>:	nop
   0x000058d991b07dce <+14>:	nop
   0x000058d991b07dcf <+15>:	nop
   0x000058d991b07dd0 <+16>:	nop
   0x000058d991b07dd1 <+17>:	nop
   0x000058d991b07dd2 <+18>:	nop
   0x000058d991b07dd3 <+19>:	nop
   0x000058d991b07dd4 <+20>:	nop
   0x000058d991b07dd5 <+21>:	mov    %rbx,0x8(%rsp)
   0x000058d991b07dda <+26>:	mov    %rdi,%rbx
   0x000058d991b07ddd <+29>:	call   0x58d991acbd30 <_ZN15CPointerManager8positionEv>
   0x000058d991b07de2 <+34>:	mov    0x8(%rsp),%rax
   0x000058d991b07de7 <+39>:	sub    %fs:0x28,%rax
   0x000058d991b07df0 <+48>:	jne    0x58d991b07dfb <_ZN13CInputManager22getMouseCoordsInternalEv+59>
   0x000058d991b07df2 <+50>:	add    $0x10,%rsp
   0x000058d991b07df6 <+54>:	mov    %rbx,%rax
   0x000058d991b07df9 <+57>:	pop    %rbx
   0x000058d991b07dfa <+58>:	ret
   0x000058d991b07dfb <+59>:	call   0x58d991850980 <__stack_chk_fail@plt>
End of assembler dump.

@vaxerski
Copy link
Member

address looks very bad. Can you post a log? Also, what does cat /proc/$(pidof Hyprland)/maps return?

@raybbian
Copy link
Contributor Author

raybbian commented Dec 25, 2024

Log:
log.txt
Maps:
maps.txt

should be same process, different process from asm above

EDIT: ones from the same process:
disassemble:

(gdb) disassemble _ZN13CInputManager22getMouseCoordsInternalEv
Dump of assembler code for function _ZN13CInputManager22getMouseCoordsInternalEv:
   0x00005826dcd45dc0 <+0>:	movabs $0x7038940999a6,%rax
   0x00005826dcd45dca <+10>:	jmp    *%rax
   0x00005826dcd45dcc <+12>:	pop    %rax
   0x00005826dcd45dcd <+13>:	nop
   0x00005826dcd45dce <+14>:	nop
   0x00005826dcd45dcf <+15>:	nop
   0x00005826dcd45dd0 <+16>:	nop
   0x00005826dcd45dd1 <+17>:	nop
   0x00005826dcd45dd2 <+18>:	nop
   0x00005826dcd45dd3 <+19>:	nop
   0x00005826dcd45dd4 <+20>:	nop
   0x00005826dcd45dd5 <+21>:	mov    %rbx,0x8(%rsp)
   0x00005826dcd45dda <+26>:	mov    %rdi,%rbx
   0x00005826dcd45ddd <+29>:	call   0x5826dcd09d30 <_ZN15CPointerManager8positionEv>
   0x00005826dcd45de2 <+34>:	mov    0x8(%rsp),%rax
   0x00005826dcd45de7 <+39>:	sub    %fs:0x28,%rax
   0x00005826dcd45df0 <+48>:	jne    0x5826dcd45dfb <_ZN13CInputManager22getMouseCoordsInternalEv+59>
   0x00005826dcd45df2 <+50>:	add    $0x10,%rsp
   0x00005826dcd45df6 <+54>:	mov    %rbx,%rax
   0x00005826dcd45df9 <+57>:	pop    %rbx
   0x00005826dcd45dfa <+58>:	ret
   0x00005826dcd45dfb <+59>:	call   0x5826dca8e980 <__stack_chk_fail@plt>
End of assembler dump.

log:
log2.txt
map:
maps2.txt

@vaxerski
Copy link
Member

[LOG] getAddressForTrampo: Returning addr 0x5826dd20c000 for page at 0x5826dd20c000
[LOG] getAddressForTrampo: Returning addr 0x5826dd20c040 for page at 0x5826dd20c000

I don't think it's the same...? You can see the addr is 0x7038940999a6 in the disasm...

@raybbian
Copy link
Contributor Author

raybbian commented Dec 25, 2024

Let me try again...

Log:
log3.txt

Maps:
maps3.txt

Disasm:

(gdb) disassemble _ZN13CInputManager22getMouseCoordsInternalEv
Dump of assembler code for function _ZN13CInputManager22getMouseCoordsInternalEv:
   0x000063ea08a64dc0 <+0>:	movabs $0x72d4096df946,%rax
   0x000063ea08a64dca <+10>:	jmp    *%rax
   0x000063ea08a64dcc <+12>:	pop    %rax
   0x000063ea08a64dcd <+13>:	nop
   0x000063ea08a64dce <+14>:	nop
   0x000063ea08a64dcf <+15>:	nop
   0x000063ea08a64dd0 <+16>:	nop
   0x000063ea08a64dd1 <+17>:	nop
   0x000063ea08a64dd2 <+18>:	nop
   0x000063ea08a64dd3 <+19>:	nop
   0x000063ea08a64dd4 <+20>:	nop
   0x000063ea08a64dd5 <+21>:	mov    %rbx,0x8(%rsp)
   0x000063ea08a64dda <+26>:	mov    %rdi,%rbx
   0x000063ea08a64ddd <+29>:	call   0x63ea08a28d30 <_ZN15CPointerManager8positionEv>
   0x000063ea08a64de2 <+34>:	mov    0x8(%rsp),%rax
   0x000063ea08a64de7 <+39>:	sub    %fs:0x28,%rax
   0x000063ea08a64df0 <+48>:	jne    0x63ea08a64dfb <_ZN13CInputManager22getMouseCoordsInternalEv+59>
   0x000063ea08a64df2 <+50>:	add    $0x10,%rsp
   0x000063ea08a64df6 <+54>:	mov    %rbx,%rax
   0x000063ea08a64df9 <+57>:	pop    %rbx
   0x000063ea08a64dfa <+58>:	ret
   0x000063ea08a64dfb <+59>:	call   0x63ea087ad980 <__stack_chk_fail@plt>
End of assembler dump.

All PID 34038

EDIT: another set where i log the fns im hooking (?) (The hook for CHyprRenderer::renderWorkspace(...) works)
maps4.txt
log4.txt

(gdb) disassemble _ZN13CInputManager22getMouseCoordsInternalEv
Dump of assembler code for function _ZN13CInputManager22getMouseCoordsInternalEv:
   0x00005951c6522dc0 <+0>:	movabs $0x742a681b6491,%rax
   0x00005951c6522dca <+10>:	jmp    *%rax
   0x00005951c6522dcc <+12>:	pop    %rax
   0x00005951c6522dcd <+13>:	nop
   0x00005951c6522dce <+14>:	nop
   0x00005951c6522dcf <+15>:	nop
   0x00005951c6522dd0 <+16>:	nop
   0x00005951c6522dd1 <+17>:	nop
   0x00005951c6522dd2 <+18>:	nop
   0x00005951c6522dd3 <+19>:	nop
   0x00005951c6522dd4 <+20>:	nop
   0x00005951c6522dd5 <+21>:	mov    %rbx,0x8(%rsp)
   0x00005951c6522dda <+26>:	mov    %rdi,%rbx
   0x00005951c6522ddd <+29>:	call   0x5951c64e6d30 <_ZN15CPointerManager8positionEv>
   0x00005951c6522de2 <+34>:	mov    0x8(%rsp),%rax
   0x00005951c6522de7 <+39>:	sub    %fs:0x28,%rax
   0x00005951c6522df0 <+48>:	jne    0x5951c6522dfb <_ZN13CInputManager22getMouseCoordsInternalEv+59>
   0x00005951c6522df2 <+50>:	add    $0x10,%rsp
   0x00005951c6522df6 <+54>:	mov    %rbx,%rax
   0x00005951c6522df9 <+57>:	pop    %rbx
   0x00005951c6522dfa <+58>:	ret
   0x00005951c6522dfb <+59>:	call   0x5951c626b980 <__stack_chk_fail@plt>
End of assembler dump.

@vaxerski
Copy link
Member

vaxerski commented Dec 25, 2024

ah right shit sorry my bad, was reading wrong, xmas moment. Can you please follow the trampoline and disassemble 64 bytes of it? (You can find it in the log, in [LOG] getAddressForTrampo: Returning addr 0x63ea08f2b000 for page at 0x63ea08f2b000 the trampo is the "returning addr ...")

I am pretty sure the trampoline has to be bad if calling original crashes.

Also, can you try not calling the original and seeing if that works? Just return some dummy 1,1 for testing.

@raybbian
Copy link
Contributor Author

raybbian commented Dec 25, 2024

I am pretty sure the trampoline has to be bad if calling original crashes.

The original crashes only on non-nested Hyprland, meaning it could have also been endbr64 (?)

Also, can you try not calling the original and seeing if that works? Just return some dummy 1,1 for testing.

Here is the hook

static Vector2D hkGetMouseCoordsInternal(void *thisptr) {
    Debug::log(LOG, "[Hyprtasking] Hooked get mouse coords internal");
    return {1, 1};
}

and trampoline location 0x5b60e4931040 from

[LOG] getAddressForTrampo: Returning addr 0x5b60e4931040 for page at 0x5b60e4931000
[LOG] [Hyprtasking] Hooked _ZN13CInputManager22getMouseCoordsInternalEv

with disasm

(gdb) x/16i 0x5b60e4931040
   0x5b60e4931040:	push   %rbx
   0x5b60e4931041:	sub    $0x10,%rsp
   0x5b60e4931045:	
    mov    -0xd894(%rip),%rsi        # 0x5b60e49237b8 <g_pPointerManager>
   0x5b60e493104c:	mov    %fs:0x28,%rbx
   0x5b60e4931055:	push   %rax
   0x5b60e4931056:	movabs $0x5b60e446adcc,%rax
   0x5b60e4931060:	jmp    *%rax
   0x5b60e4931062:	add    %al,(%rax)
   0x5b60e4931064:	add    %al,(%rax)
   0x5b60e4931066:	add    %al,(%rax)
   0x5b60e4931068:	add    %al,(%rax)
   0x5b60e493106a:	add    %al,(%rax)
   0x5b60e493106c:	add    %al,(%rax)
   0x5b60e493106e:	add    %al,(%rax)
   0x5b60e4931070:	add    %al,(%rax)
   0x5b60e4931072:	add    %al,(%rax)

... I've also just realized that the hook does get called (sometimes). Whoops.

The hook gets triggered when I left click on my plugin's overlay. This is the code that executes when that happens:

static void onMouseButton(void *thisptr, SCallbackInfo &info, std::any args) {
    const PHLMONITOR pMonitor = g_pCompositor->getMonitorFromCursor();
    const auto view = getViewForMonitor(pMonitor);
    if (pMonitor == nullptr || view == nullptr || !view->isActive())
        return;

    info.cancelled = true;

    const auto e = std::any_cast<IPointer::SButtonEvent>(args);
    if (e.button != BTN_LEFT)
        return;
    const bool pressed = e.state == WL_POINTER_BUTTON_STATE_PRESSED;
    if (pressed) {
        g_pKeybindManager->changeMouseBindMode(MBIND_MOVE);
    } else {
        g_pKeybindManager->changeMouseBindMode(MBIND_INVALID);
    }
}

changeMouseBindMode does call getMouseCoordsInternal, so I believe the hook itself works fine (?)

However, the hook is not called whenever the mouse moves. This is odd because I have a mouseMove callback onMouseMove that is being called from (I believe) here.

To call onMouseMove, doesn't mouseMoveUnified need to call getMouseCoordsInternal() first?

void CInputManager::mouseMoveUnified(uint32_t time, bool refocus, bool mouse) {
    m_bLastInputMouse = mouse;

    if (!g_pCompositor->m_bReadyToProcess || g_pCompositor->m_bIsShuttingDown || g_pCompositor->m_bUnsafeState)
        return;

    Vector2D const mouseCoords        = getMouseCoordsInternal();
    auto const     MOUSECOORDSFLOORED = mouseCoords.floor();

    // ...   

    EMIT_HOOK_EVENT_CANCELLABLE("mouseMove", MOUSECOORDSFLOORED);
}

... what?

This is likely a skill issue on my part - I really appreciate your help w everything

happy holidays!

@vaxerski
Copy link
Member

It genuinely isn't - this is unfortunately the tradeoff of hooks. Assembly debugging is very non-trivial :P

Anyways, I assume that it is being called in debug on mouse move.

The original crashes only on non-nested Hyprland, meaning it could have also been endbr64 (?)

Let's get this straight:
Release, non-nested:

  • original crashes
  • hook doesnt get called on mouse move

Debug, nested:

  • original works
  • hook gets called on mouse move

Correct?

Now, is "release non nested" a "git, with fcf-protection=none", or "pulled from arch repos"?

If it's arch repos, try release, non-nested, with fcf-protection=none.

@raybbian
Copy link
Contributor Author

raybbian commented Dec 25, 2024

Anyways, I assume that it is being called in debug on mouse move.

Yep

Correct?

That is the case. "Original crashes" is a SIGSEGV in onMouseMove (because my onMouseMove calls the original getMouseCoordsInternal), which causes Hyprland to unload the plugin.

Now, is "release non nested" a "git, with fcf-protection=none", or "pulled from arch repos"?

"Release non-nested" is the hyprland arch package.

If it's arch repos, try release, non-nested, with fcf-protection=none.

Looks like being nested/non-nested has a difference: git checked out to v0.46.2 with fcf-protection=none added to add_compile_options of CMakeLists.txt running non-nested also causes a crash.

Will post disasm shortly

@vaxerski
Copy link
Member

vaxerski commented Dec 25, 2024

I have a feeling it might actually be inlining, but that wouldn't explain the crashes. (only the "not called")

@raybbian
Copy link
Contributor Author

raybbian commented Dec 25, 2024

Disasm before plugin load

(gdb) disassemble _ZN13CInputManager22getMouseCoordsInternalEv
Dump of assembler code for function _ZN13CInputManager22getMouseCoordsInternalEv:
   0x000059e3a2b3edc0 <+0>:     push   %rbx
   0x000059e3a2b3edc1 <+1>:     sub    $0x10,%rsp
   0x000059e3a2b3edc5 <+5>:     mov    0x4b89ec(%rip),%rsi        # 0x59e3a2ff77b8 <g_pPointerManager>
   0x000059e3a2b3edcc <+12>:    mov    %fs:0x28,%rbx
   0x000059e3a2b3edd5 <+21>:    mov    %rbx,0x8(%rsp)
   0x000059e3a2b3edda <+26>:    mov    %rdi,%rbx
   0x000059e3a2b3eddd <+29>:    call   0x59e3a2b02d30 <_ZN15CPointerManager8positionEv>
   0x000059e3a2b3ede2 <+34>:    mov    0x8(%rsp),%rax
   0x000059e3a2b3ede7 <+39>:    sub    %fs:0x28,%rax
   0x000059e3a2b3edf0 <+48>:    jne    0x59e3a2b3edfb <_ZN13CInputManager22getMouseCoordsInternalEv+59>
   0x000059e3a2b3edf2 <+50>:    add    $0x10,%rsp
   0x000059e3a2b3edf6 <+54>:    mov    %rbx,%rax
   0x000059e3a2b3edf9 <+57>:    pop    %rbx
   0x000059e3a2b3edfa <+58>:    ret
   0x000059e3a2b3edfb <+59>:    call   0x59e3a2887980 <__stack_chk_fail@plt>
End of assembler dump.

Disasm after plugin load

Dump of assembler code for function _ZN13CInputManager22getMouseCoordsInternalEv:
   0x000059e3a2b3edc0 <+0>:     movabs $0x7d4206008491,%rax
   0x000059e3a2b3edca <+10>:    jmp    *%rax
   0x000059e3a2b3edcc <+12>:    pop    %rax
   0x000059e3a2b3edcd <+13>:    nop
   0x000059e3a2b3edce <+14>:    nop
   0x000059e3a2b3edcf <+15>:    nop
   0x000059e3a2b3edd0 <+16>:    nop
   0x000059e3a2b3edd1 <+17>:    nop
   0x000059e3a2b3edd2 <+18>:    nop
   0x000059e3a2b3edd3 <+19>:    nop
   0x000059e3a2b3edd4 <+20>:    nop
   0x000059e3a2b3edd5 <+21>:    mov    %rbx,0x8(%rsp)
   0x000059e3a2b3edda <+26>:    mov    %rdi,%rbx
   0x000059e3a2b3eddd <+29>:    call   0x59e3a2b02d30 <_ZN15CPointerManager8positionEv>
   0x000059e3a2b3ede2 <+34>:    mov    0x8(%rsp),%rax
   0x000059e3a2b3ede7 <+39>:    sub    %fs:0x28,%rax
   0x000059e3a2b3edf0 <+48>:    jne    0x59e3a2b3edfb <_ZN13CInputManager22getMouseCoordsInternalEv+59>
   0x000059e3a2b3edf2 <+50>:    add    $0x10,%rsp
   0x000059e3a2b3edf6 <+54>:    mov    %rbx,%rax
   0x000059e3a2b3edf9 <+57>:    pop    %rbx
   0x000059e3a2b3edfa <+58>:    ret
   0x000059e3a2b3edfb <+59>:    call   0x59e3a2887980 <__stack_chk_fail@plt>
End of assembler dump.

Disasm of trampoline (address from logs):

(gdb) x/16i 0x403bc100
   0x403bc100:  push   %rbx
   0x403bc101:  sub    $0x10,%rsp
   0x403bc105:  mov    0x62c3b6ac(%rip),%rsi        # 0xa2ff77b8
   0x403bc10c:  mov    %fs:0x28,%rbx
   0x403bc115:  push   %rax
   0x403bc116:  movabs $0x59e3a2b3edcc,%rax
   0x403bc120:  jmp    *%rax
   0x403bc122:  add    %al,(%rax)
   0x403bc124:  add    %al,(%rax)
   0x403bc126:  add    %al,(%rax)
   0x403bc128:  add    %al,(%rax)
   0x403bc12a:  add    %al,(%rax)
   0x403bc12c:  add    %al,(%rax)
   0x403bc12e:  add    %al,(%rax)
   0x403bc130:  add    %al,(%rax)
   0x403bc132:  add    %al,(%rax

This is for non-nested git release v0.46.2, moving mouse when overlay is active (calling original fn) causes crash and plugin unload.

@vaxerski
Copy link
Member

vaxerski commented Dec 25, 2024

hahaha okay so we got why it crashes :) thanks for the disasm, will try to fix the crash (tomorrow maybe, christmas)

The "not called" is likely unfixable, unless we explicitly mark the fn as no inline. I am unsure if that's a good idea though.

Wait, trampo address a bit smal, can you also pass a log? Will be useful for tomorrow. (its midnight heh)

@raybbian
Copy link
Contributor Author

raybbian commented Dec 25, 2024

The "not called" is likely unfixable, unless we explicitly mark the fn as no inline. I am unsure if that's a good idea though.

Unfortunate :( to the workarounds I go!

hahaha okay so we got why it crashes :) thanks for the disasm, will try to fix the crash (tomorrow maybe, christmas)

Would love a short explanation if you have the time ❤️

Wait, trampo address a bit smal, can you also pass a log? Will be useful for tomorrow. (its midnight heh)

log5.txt

@vaxerski
Copy link
Member

Would love a short explanation if you have the time ❤️

You have some weird page allocations before the code sector so hyprland tries to use them as anchors for the trampolines, where it should use the code sections. Fixed that, should not crash anymore.

@raybbian
Copy link
Contributor Author

I can confirm that calling the original function no longer crashes on non-nested release git.

Interestingly, compiling Hyprland with (in InputManager.cpp)

Vector2D __attribute__((noinline)) CInputManager::getMouseCoordsInternal() {
    return g_pPointerManager->position();
}

and (in InputManager.hpp)

Vector2D __attribute__((noinline)) getMouseCoordsInternal();

still results in my function hook only executing on mouse click. Shouldn't this prevent an inline? The onMouseMove event hook is triggered and my callback is called, but my hook for getMouseCoordsInternal is not.

For documentation: I've gotten around this by using g_pPointerManager->warpTo(...) before and after calling interal fns like onBeginWindowDrag, which works for my use case. Curious as to why the hook doesn't get called still...

@vaxerski
Copy link
Member

attach gdb and put a breakpoint on _ZN13CInputManager22getMouseCoordsInternalEv, check if it gets called... if not, I assume it got inlined.

@raybbian
Copy link
Contributor Author

Doesn't break on mouse move, but breaks on mouse click - probably inlined.

Thanks for the help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants