Compare commits
20 Commits
96518634fb
...
c10639fd46
Author | SHA1 | Date | |
---|---|---|---|
c10639fd46 | |||
73e4a90d3a | |||
4266196b2d | |||
16e9efa4f5 | |||
5b2c610527 | |||
e382ca102a | |||
05b9a021dc | |||
d503a69239 | |||
52e0963cc7 | |||
81eb7da837 | |||
141a558dd8 | |||
039cd50187 | |||
63a445cbba | |||
3e9ae003b7 | |||
017c82e561 | |||
4059906e78 | |||
3fadb5aa5a | |||
ad3325548d | |||
21d3181e00 | |||
9233bcc513 |
18
.github/workflows/stale.yml
vendored
Normal file
18
.github/workflows/stale.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 5 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v4
|
||||
with:
|
||||
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 15 days.'
|
||||
days-before-stale: 60
|
||||
days-before-close: 15
|
||||
exempt-all-milestones: true
|
||||
exempt-issue-labels: 'pinned'
|
||||
exempt-pr-labels: 'pinned'
|
@ -11,13 +11,13 @@ module Common =
|
||||
let UC_API_MINOR = 0
|
||||
|
||||
let UC_API_PATCH = 0
|
||||
let UC_API_EXTRA = 5
|
||||
let UC_API_EXTRA = 6
|
||||
let UC_VERSION_MAJOR = 2
|
||||
|
||||
let UC_VERSION_MINOR = 0
|
||||
|
||||
let UC_VERSION_PATCH = 0
|
||||
let UC_VERSION_EXTRA = 5
|
||||
let UC_VERSION_EXTRA = 6
|
||||
let UC_SECOND_SCALE = 1000000
|
||||
let UC_MILISECOND_SCALE = 1000
|
||||
let UC_ARCH_ARM = 1
|
||||
@ -38,6 +38,7 @@ module Common =
|
||||
let UC_MODE_THUMB = 16
|
||||
let UC_MODE_MCLASS = 32
|
||||
let UC_MODE_V8 = 64
|
||||
let UC_MODE_ARMBE8 = 128
|
||||
let UC_MODE_ARM926 = 128
|
||||
let UC_MODE_ARM946 = 256
|
||||
let UC_MODE_ARM1176 = 512
|
||||
|
@ -6,13 +6,13 @@ const (
|
||||
API_MINOR = 0
|
||||
|
||||
API_PATCH = 0
|
||||
API_EXTRA = 5
|
||||
API_EXTRA = 6
|
||||
VERSION_MAJOR = 2
|
||||
|
||||
VERSION_MINOR = 0
|
||||
|
||||
VERSION_PATCH = 0
|
||||
VERSION_EXTRA = 5
|
||||
VERSION_EXTRA = 6
|
||||
SECOND_SCALE = 1000000
|
||||
MILISECOND_SCALE = 1000
|
||||
ARCH_ARM = 1
|
||||
@ -33,6 +33,7 @@ const (
|
||||
MODE_THUMB = 16
|
||||
MODE_MCLASS = 32
|
||||
MODE_V8 = 64
|
||||
MODE_ARMBE8 = 128
|
||||
MODE_ARM926 = 128
|
||||
MODE_ARM946 = 256
|
||||
MODE_ARM1176 = 512
|
||||
|
@ -8,13 +8,13 @@ public interface UnicornConst {
|
||||
public static final int UC_API_MINOR = 0;
|
||||
|
||||
public static final int UC_API_PATCH = 0;
|
||||
public static final int UC_API_EXTRA = 5;
|
||||
public static final int UC_API_EXTRA = 6;
|
||||
public static final int UC_VERSION_MAJOR = 2;
|
||||
|
||||
public static final int UC_VERSION_MINOR = 0;
|
||||
|
||||
public static final int UC_VERSION_PATCH = 0;
|
||||
public static final int UC_VERSION_EXTRA = 5;
|
||||
public static final int UC_VERSION_EXTRA = 6;
|
||||
public static final int UC_SECOND_SCALE = 1000000;
|
||||
public static final int UC_MILISECOND_SCALE = 1000;
|
||||
public static final int UC_ARCH_ARM = 1;
|
||||
@ -35,6 +35,7 @@ public interface UnicornConst {
|
||||
public static final int UC_MODE_THUMB = 16;
|
||||
public static final int UC_MODE_MCLASS = 32;
|
||||
public static final int UC_MODE_V8 = 64;
|
||||
public static final int UC_MODE_ARMBE8 = 128;
|
||||
public static final int UC_MODE_ARM926 = 128;
|
||||
public static final int UC_MODE_ARM946 = 256;
|
||||
public static final int UC_MODE_ARM1176 = 512;
|
||||
|
@ -9,13 +9,13 @@ const UC_API_MAJOR = 2;
|
||||
UC_API_MINOR = 0;
|
||||
|
||||
UC_API_PATCH = 0;
|
||||
UC_API_EXTRA = 5;
|
||||
UC_API_EXTRA = 6;
|
||||
UC_VERSION_MAJOR = 2;
|
||||
|
||||
UC_VERSION_MINOR = 0;
|
||||
|
||||
UC_VERSION_PATCH = 0;
|
||||
UC_VERSION_EXTRA = 5;
|
||||
UC_VERSION_EXTRA = 6;
|
||||
UC_SECOND_SCALE = 1000000;
|
||||
UC_MILISECOND_SCALE = 1000;
|
||||
UC_ARCH_ARM = 1;
|
||||
@ -36,6 +36,7 @@ const UC_API_MAJOR = 2;
|
||||
UC_MODE_THUMB = 16;
|
||||
UC_MODE_MCLASS = 32;
|
||||
UC_MODE_V8 = 64;
|
||||
UC_MODE_ARMBE8 = 128;
|
||||
UC_MODE_ARM926 = 128;
|
||||
UC_MODE_ARM946 = 256;
|
||||
UC_MODE_ARM1176 = 512;
|
||||
|
@ -29,7 +29,7 @@ SRC_DIR = os.path.join(ROOT_DIR, 'src')
|
||||
UC_DIR = os.path.join(ROOT_DIR, '../..')
|
||||
BUILD_DIR = os.path.join(UC_DIR, 'build_python')
|
||||
|
||||
VERSION = "2.0.0rc5.post1"
|
||||
VERSION = "2.0.0rc6"
|
||||
|
||||
if SYSTEM == 'darwin':
|
||||
LIBRARY_FILE = "libunicorn.dylib"
|
||||
|
@ -4,13 +4,13 @@ UC_API_MAJOR = 2
|
||||
UC_API_MINOR = 0
|
||||
|
||||
UC_API_PATCH = 0
|
||||
UC_API_EXTRA = 5
|
||||
UC_API_EXTRA = 6
|
||||
UC_VERSION_MAJOR = 2
|
||||
|
||||
UC_VERSION_MINOR = 0
|
||||
|
||||
UC_VERSION_PATCH = 0
|
||||
UC_VERSION_EXTRA = 5
|
||||
UC_VERSION_EXTRA = 6
|
||||
UC_SECOND_SCALE = 1000000
|
||||
UC_MILISECOND_SCALE = 1000
|
||||
UC_ARCH_ARM = 1
|
||||
@ -31,6 +31,7 @@ UC_MODE_ARM = 0
|
||||
UC_MODE_THUMB = 16
|
||||
UC_MODE_MCLASS = 32
|
||||
UC_MODE_V8 = 64
|
||||
UC_MODE_ARMBE8 = 128
|
||||
UC_MODE_ARM926 = 128
|
||||
UC_MODE_ARM946 = 256
|
||||
UC_MODE_ARM1176 = 512
|
||||
|
@ -6,13 +6,13 @@ module UnicornEngine
|
||||
UC_API_MINOR = 0
|
||||
|
||||
UC_API_PATCH = 0
|
||||
UC_API_EXTRA = 5
|
||||
UC_API_EXTRA = 6
|
||||
UC_VERSION_MAJOR = 2
|
||||
|
||||
UC_VERSION_MINOR = 0
|
||||
|
||||
UC_VERSION_PATCH = 0
|
||||
UC_VERSION_EXTRA = 5
|
||||
UC_VERSION_EXTRA = 6
|
||||
UC_SECOND_SCALE = 1000000
|
||||
UC_MILISECOND_SCALE = 1000
|
||||
UC_ARCH_ARM = 1
|
||||
@ -33,6 +33,7 @@ module UnicornEngine
|
||||
UC_MODE_THUMB = 16
|
||||
UC_MODE_MCLASS = 32
|
||||
UC_MODE_V8 = 64
|
||||
UC_MODE_ARMBE8 = 128
|
||||
UC_MODE_ARM926 = 128
|
||||
UC_MODE_ARM946 = 256
|
||||
UC_MODE_ARM1176 = 512
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "unicorn-engine"
|
||||
version = "2.0.0-rc5.post1"
|
||||
version = "2.0.0-rc6"
|
||||
authors = ["Ziqiao Kong", "Lukas Seidel"]
|
||||
documentation = "https://github.com/unicorn-engine/unicorn/wiki"
|
||||
edition = "2021"
|
||||
@ -24,8 +24,14 @@ bitflags = "1.3"
|
||||
libc = "0.2"
|
||||
|
||||
[build-dependencies]
|
||||
build-helper = "0.1"
|
||||
reqwest = { version = "0.11", features = ["blocking"] }
|
||||
flate2 = "1.0.22"
|
||||
tar = "0.4.37"
|
||||
bytes = "1.1.0"
|
||||
reqwest = { optional = true, version = "0.11", features = ["blocking"] }
|
||||
flate2 = { optional = true, version = "1.0" }
|
||||
tar = { optional = true, version = "0.4" }
|
||||
bytes = { optional = true, version = "1" }
|
||||
pkg-config = { optional = true, version = "0.3" }
|
||||
|
||||
[features]
|
||||
default = ["build_unicorn_cmake"]
|
||||
|
||||
use_system_unicorn = ["pkg-config"]
|
||||
build_unicorn_cmake = ["reqwest", "flate2", "tar", "bytes"]
|
||||
|
@ -1,10 +1,19 @@
|
||||
#[cfg(feature = "build_unicorn_cmake")]
|
||||
use bytes::Buf;
|
||||
#[cfg(feature = "build_unicorn_cmake")]
|
||||
use flate2::read::GzDecoder;
|
||||
#[cfg(feature = "use_system_unicorn")]
|
||||
use pkg_config;
|
||||
#[cfg(feature = "build_unicorn_cmake")]
|
||||
use reqwest::header::USER_AGENT;
|
||||
#[cfg(feature = "build_unicorn_cmake")]
|
||||
use std::path::{Path, PathBuf};
|
||||
#[cfg(feature = "build_unicorn_cmake")]
|
||||
use std::{env, process::Command};
|
||||
#[cfg(feature = "build_unicorn_cmake")]
|
||||
use tar::Archive;
|
||||
|
||||
#[cfg(feature = "build_unicorn_cmake")]
|
||||
fn find_unicorn(unicorn_dir: &Path) -> Option<PathBuf> {
|
||||
for entry in std::fs::read_dir(unicorn_dir).ok()? {
|
||||
let entry = entry.unwrap();
|
||||
@ -18,11 +27,13 @@ fn find_unicorn(unicorn_dir: &Path) -> Option<PathBuf> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(feature = "build_unicorn_cmake")]
|
||||
fn out_dir() -> PathBuf {
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
Path::new(&out_dir).to_path_buf()
|
||||
}
|
||||
|
||||
#[cfg(feature = "build_unicorn_cmake")]
|
||||
fn download_unicorn() -> PathBuf {
|
||||
// https://docs.github.com/en/rest/reference/repos#download-a-repository-archive-tar
|
||||
let pkg_version;
|
||||
@ -51,8 +62,9 @@ fn download_unicorn() -> PathBuf {
|
||||
find_unicorn(&out_dir).unwrap()
|
||||
}
|
||||
|
||||
#[cfg(feature = "build_unicorn_cmake")]
|
||||
#[allow(clippy::branches_sharing_code)]
|
||||
fn main() {
|
||||
fn build_with_cmake() {
|
||||
let profile = env::var("PROFILE").unwrap();
|
||||
|
||||
if let Some(unicorn_dir) = find_unicorn(&out_dir()) {
|
||||
@ -183,3 +195,16 @@ fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=src");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if cfg!(feature = "use_system_unicorn") {
|
||||
#[cfg(feature = "use_system_unicorn")]
|
||||
pkg_config::Config::new()
|
||||
.atleast_version("2")
|
||||
.probe("unicorn")
|
||||
.expect("Could not find system unicorn2");
|
||||
} else {
|
||||
#[cfg(feature = "build_unicorn_cmake")]
|
||||
build_with_cmake();
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ msbuild unicorn.sln -p:Plaform=Win32 -p:Configuration=Release
|
||||
|
||||
## Cross build with NDK
|
||||
|
||||
To build Unicorn2 on the Android platform, firstly you need to download [NDK](https://developer.android.com/ndk/downloads).
|
||||
To cross-build and run Unicorn2 on the Android platform, firstly you need to download [NDK](https://developer.android.com/ndk/downloads).
|
||||
|
||||
For newer NDK, please make sure your cmake version is above 3.19.
|
||||
|
||||
@ -68,7 +68,7 @@ You may get the possible values from this [page](https://developer.android.com/n
|
||||
|
||||
Unicorn2 support cross-build for `armeabi-v7a`, `arm64-v8a`, `x86` and `x86_64`.
|
||||
|
||||
Note the build is only tested and guaranteed to work under Linux, however, other systems may still work.
|
||||
Note the build is only tested and guaranteed to work under Linux and macOS, however, other systems may still work.
|
||||
|
||||
## Cross build from Linux host to Windows, with Mingw
|
||||
|
||||
@ -97,15 +97,16 @@ This requires MSYS2 to be installed on the Windows machine. You need to download
|
||||
Then from MSYS2 console, install packages below:
|
||||
|
||||
```bash
|
||||
pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake
|
||||
pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja
|
||||
```
|
||||
|
||||
- Build Unicorn and samples with the following commands.
|
||||
|
||||
```bash
|
||||
export PATH=/mingw64/bin:$PATH
|
||||
mkdir build; cd build
|
||||
/mingw64/bin/cmake .. -G "MSYS Makefiles" -DCMAKE_C_COMPILER=/mingw64/bin/gcc.exe -DCMAKE_MAKE_PROGRAM=/mingw64/bin/mingw32-make.exe -DCMAKE_AR=/mingw64/bin/ar.exe -DUNICORN_ARCH=x86
|
||||
mingw32-make
|
||||
/mingw64/bin/cmake .. -G "Ninja"
|
||||
ninja -C .
|
||||
```
|
||||
|
||||
Note that the way to build on MSYS changes as time goes, please keep in mind that always use the cmake shipped with mingw64 and choose MSYS Makefiles.
|
||||
|
68
docs/FAQ.md
Normal file
68
docs/FAQ.md
Normal file
@ -0,0 +1,68 @@
|
||||
## Why is my execution so slow?
|
||||
|
||||
Typically, it’s due to
|
||||
|
||||
- Instrumenting every instruction executed.
|
||||
- Instrumenting every memory access.
|
||||
|
||||
Optimize your program with less instrumentation.
|
||||
|
||||
## Why do I get a wrong PC after emulation stops?
|
||||
|
||||
PC is only guaranteed to be correct if you install `UC_HOOK_CODE`. This is due to the fact that updating PC is a big performance overhead during emulation.
|
||||
|
||||
## I get an “Unhandled CPU Exception”, why?
|
||||
|
||||
Unicorn is a pure CPU emulator and usually it’s due to no handler registered for instructions like `syscall` and `SVC`. If you expect system emulation, you probably would like [qiling framework](https://github.com/qilingframework/qiling).
|
||||
|
||||
## I would like to instrument a specific instruction but get a `UC_ERR_HOOK`, why?
|
||||
|
||||
Currently, only a small subset of the instructions can be instrumented.
|
||||
|
||||
On x86, all available instructions are: `in` `out` `syscall` `sysenter` `cpuid`.
|
||||
|
||||
## Emulating some instructions gives an error, what should I do?
|
||||
|
||||
1. Some instructions are not enabled by default on some architectures. For example, you have to setup CSR on RISC-V or VFP on ARM before emulating floating-point instructions. Refer to the corresponding manual to check if you leave out possible switches in special registers.
|
||||
2. If you are on ARM, please check whether you are emulating a THUMB instruction. If so, please use `UC_MODE_THUMB` and make sure the starting address is odd.
|
||||
3. If either is not the case, it might be some newer instruction sets that qemu5 doesn’t support.
|
||||
|
||||
If you are still using Unicorn1, please upgrade to Unicorn2 for better support.
|
||||
|
||||
## I can't recover from unmapped read/write even I return `true` in the hook, why?
|
||||
|
||||
This is a minor change in memory hooks behavior between Unicorn1 and Unicorn2. To gracefully recover from memory read/write error, you have to map the invalid memory before you return true.
|
||||
|
||||
It is due to the fact that, if users return `true` without memory mapping set up correctly, we don't know what to do next. In Unicorn1, the behavior is __undefined__ in this case but in Unicorn2 we would like to force users to set up memory mapping in the hook to continue execution.
|
||||
|
||||
See the [sample](https://github.com/unicorn-engine/unicorn/blob/c05fbb7e63aed0b60fc2888e08beceb17bce8ac4/samples/sample_x86.c#L1379-L1393) for details.
|
||||
|
||||
## How to emulate interrupts (or ticks) with Unicorn?
|
||||
|
||||
As stated, Unicorn is a pure CPU emulator. For such emulation, you have two choices:
|
||||
|
||||
- Use the `timeout` parameter of `uc_emu_start`
|
||||
- Use the `count` parameter of `uc_emu_start`
|
||||
|
||||
After emulation stops, you may check anything you feel interested and resume emulation accordingly.
|
||||
|
||||
Note that for cortex-m `exec_return`, Unicorn has a magic software exception with interrupt number 8. You may register a hook to handle that.
|
||||
|
||||
## Why not keep up the upstream qemu?
|
||||
|
||||
To provide end users with simple API, Unicorn does lots of dirty hacks within qemu code which prevents it from sync painlessly.
|
||||
|
||||
## Is there anyway to disable softmmu to speed up execution?
|
||||
|
||||
Yes, it’s possible but that is not Unicorn’s goal and there is no simple switch in qemu to disable softmmu.
|
||||
|
||||
## I'd like to make contributions, where do I start?
|
||||
|
||||
See [milestones](https://github.com/unicorn-engine/unicorn/milestones) and [coding convention](https://github.com/unicorn-engine/unicorn/wiki/Coding-Convention
|
||||
).
|
||||
|
||||
Be sure to send pull requests for our **dev** branch only.
|
||||
|
||||
## Which qemu version is Unicorn based on?
|
||||
|
||||
Prior to 2.0.0, Unicorn is based on qemu 2.2.1. After that, Unicorn is based on qemu 5.0.1.
|
@ -72,7 +72,7 @@ typedef size_t uc_hook;
|
||||
#define UC_API_MAJOR 2
|
||||
#define UC_API_MINOR 0
|
||||
#define UC_API_PATCH 0
|
||||
#define UC_API_EXTRA 5
|
||||
#define UC_API_EXTRA 6
|
||||
|
||||
// Unicorn package version
|
||||
#define UC_VERSION_MAJOR UC_API_MAJOR
|
||||
|
@ -2192,6 +2192,10 @@ ARMCPU *cpu_arm_init(struct uc_struct *uc)
|
||||
// Big endian code access.
|
||||
env->cp15.sctlr_ns |= SCTLR_B;
|
||||
}
|
||||
|
||||
// Backward compatiblity, start arm CPU in non-secure state.
|
||||
env->cp15.scr_el3 |= SCR_NS;
|
||||
|
||||
arm_rebuild_hflags(env);
|
||||
|
||||
return cpu;
|
||||
|
@ -378,6 +378,9 @@ ARMCPU *cpu_aarch64_init(struct uc_struct *uc)
|
||||
}
|
||||
}
|
||||
|
||||
// Backward compatability to enable FULL 64bits address space.
|
||||
env->pstate = PSTATE_MODE_EL1h;
|
||||
|
||||
arm_rebuild_hflags(env);
|
||||
|
||||
return cpu;
|
||||
|
@ -7927,7 +7927,9 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask,
|
||||
* In a V8 implementation, it is permitted for privileged software to
|
||||
* change the CPSR A/F bits regardless of the SCR.AW/FW bits.
|
||||
*/
|
||||
if (write_type != CPSRWriteRaw && !arm_feature(env, ARM_FEATURE_V8) &&
|
||||
if (write_type != CPSRWriteByUnicorn &&
|
||||
write_type != CPSRWriteRaw &&
|
||||
!arm_feature(env, ARM_FEATURE_V8) &&
|
||||
arm_feature(env, ARM_FEATURE_EL3) &&
|
||||
!arm_feature(env, ARM_FEATURE_EL2) &&
|
||||
!arm_is_secure(env)) {
|
||||
|
@ -248,6 +248,12 @@ static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value)
|
||||
case UC_ARM_REG_FPEXC:
|
||||
*(int32_t *)value = env->vfp.xregs[ARM_VFP_FPEXC];
|
||||
break;
|
||||
case UC_ARM_REG_FPSCR:
|
||||
*(int32_t *)value = vfp_get_fpscr(env);
|
||||
break;
|
||||
case UC_ARM_REG_FPSID:
|
||||
*(int32_t *)value = env->vfp.xregs[ARM_VFP_FPSID];
|
||||
break;
|
||||
case UC_ARM_REG_IPSR:
|
||||
*(int32_t *)value = v7m_mrs_xpsr(env, 5);
|
||||
break;
|
||||
@ -353,6 +359,12 @@ static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value)
|
||||
case UC_ARM_REG_FPEXC:
|
||||
env->vfp.xregs[ARM_VFP_FPEXC] = *(int32_t *)value;
|
||||
break;
|
||||
case UC_ARM_REG_FPSCR:
|
||||
vfp_set_fpscr(env, *(int32_t *)value);
|
||||
break;
|
||||
case UC_ARM_REG_FPSID:
|
||||
env->vfp.xregs[ARM_VFP_FPSID] = *(int32_t *)value;
|
||||
break;
|
||||
case UC_ARM_REG_IPSR:
|
||||
v7m_msr_xpsr(env, 0b1000, 5, *(uint32_t *)value);
|
||||
break;
|
||||
|
@ -491,13 +491,13 @@ static void test_arm_not_allow_privilege_escalation()
|
||||
static void test_arm_mrc()
|
||||
{
|
||||
uc_engine *uc;
|
||||
// mrc p15, #0, r0, c1, c1, #0
|
||||
char code[] = "\x11\x0F\x11\xEE";
|
||||
// mrc p15, #0, r1, c13, c0, #3
|
||||
char code[] = "\x1d\xee\x70\x1f";
|
||||
|
||||
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_ARM, code, sizeof(code) - 1,
|
||||
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB, code, sizeof(code) - 1,
|
||||
UC_CPU_ARM_MAX);
|
||||
|
||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||
OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0));
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
Reference in New Issue
Block a user