| /* Determine the protection of a virtual memory area. | |
| Copyright (C) 2024-2026 Free Software Foundation, Inc. | |
| This file is free software: you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published | |
| by the Free Software Foundation; either version 2 of the License, | |
| or (at your option) any later version. | |
| This file is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program. If not, see <https://www.gnu.org/licenses/>. */ | |
| /* Written by Bruno Haible <bruno@clisp.org>, 2024. */ | |
| #include <config.h> | |
| /* Specification. */ | |
| #include "vma-prot.h" | |
| #include <stdint.h> | |
| struct locals | |
| { | |
| /* The common protections seen so far. */ | |
| unsigned int prot_so_far; | |
| /* The remaining address interval. | |
| remaining_start <= remaining_end-1. */ | |
| uintptr_t remaining_start; | |
| uintptr_t remaining_end; | |
| }; | |
| static int | |
| callback (void *data, uintptr_t start, uintptr_t end, unsigned int flags) | |
| { | |
| struct locals *l = (struct locals *) data; | |
| if (start > l->remaining_start) | |
| { | |
| /* The interval [remaining_start, min (remaining_end, start)) is | |
| unmapped. */ | |
| l->prot_so_far = 0; | |
| return 1; | |
| } | |
| if (end - 1 < l->remaining_start) | |
| /* The interval [start,end) lies before [remaining_start,remaining_end). */ | |
| return 0; | |
| /* Here start <= remaining_start <= remaining_end-1 | |
| and remaining_start <= end-1, | |
| hence start <= remaining_start <= min (end-1, remaining_end-1). | |
| So, the two intervals intersect. */ | |
| l->prot_so_far &= flags; | |
| if (l->prot_so_far == 0) | |
| return 1; | |
| if (l->remaining_end - 1 <= end - 1) | |
| /* Done. */ | |
| return 1; | |
| /* Trim the remaining address interval. */ | |
| l->remaining_start = end; | |
| return 0; | |
| } | |
| int | |
| get_vma_prot (void *start, size_t size) | |
| { | |
| uintptr_t start_address = (uintptr_t) start; | |
| struct locals l; | |
| l.prot_so_far = VMA_PROT_READ | VMA_PROT_WRITE | VMA_PROT_EXECUTE; | |
| l.remaining_start = start_address; | |
| l.remaining_end = start_address + size; | |
| if (l.remaining_end < l.remaining_start) | |
| /* Invalid arguments. */ | |
| return -1; | |
| if (l.remaining_end > l.remaining_start) | |
| { | |
| if (vma_iterate (callback, &l) < 0) | |
| return -1; | |
| } | |
| return l.prot_so_far; | |
| } |