-
-
Notifications
You must be signed in to change notification settings - Fork 432
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
Add Address
methodmap
#1841
base: master
Are you sure you want to change the base?
Add Address
methodmap
#1841
Changes from all commits
fa26f4e
3849b01
0e27880
5bbc5a8
8991e25
1931e32
3630f5f
077d7ae
d263124
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -816,6 +816,143 @@ enum NumberType | |
//memory addresses below 0x10000 are automatically considered invalid for dereferencing | ||
#define VALID_MINIMUM_MEMORY_ADDRESS 0x10000 | ||
|
||
static inline void *GetAddress(cell_t caddr, cell_t coffset) | ||
{ | ||
#ifdef PLATFORM_X86 | ||
return reinterpret_cast<void *>(caddr + coffset); | ||
#else | ||
return pseudoAddr.FromPseudoAddress((uint32_t)caddr, (uint32_t)coffset); | ||
#endif | ||
} | ||
|
||
static inline bool IsAddressValidRange(void *addr) | ||
{ | ||
return addr != NULL && reinterpret_cast<uintptr_t>(addr) >= VALID_MINIMUM_MEMORY_ADDRESS; | ||
} | ||
|
||
static inline int GetAddressAccess(void *addr) | ||
{ | ||
int bits; | ||
|
||
return SourceHook::GetPageBits(addr, &bits) ? bits : 0; | ||
} | ||
|
||
static inline bool SetAddressAccess(void *addr, size_t len, int access) | ||
{ | ||
return SourceHook::SetMemAccess(addr, len, access); | ||
} | ||
|
||
// Very slowly if iterate by each address cell. | ||
template <int A /* By SH_MEM_* defines. */> | ||
static inline bool HasAddressAccess(void *addr) | ||
{ | ||
return (GetAddressAccess(addr) & A) == A; | ||
} | ||
|
||
template <typename T> | ||
static inline cell_t ReadSecureAddressCell(IPluginContext *pContext, cell_t caddr, cell_t coffset) | ||
{ | ||
void *addr = GetAddress(caddr, coffset); | ||
|
||
if (!IsAddressValidRange(addr)) | ||
{ | ||
#ifdef _DEBUG | ||
return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory (base is 0x%x, offset is 0x%x, read block size is %d)", addr, caddr, coffset, sizeof(T)); | ||
#else | ||
return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory", addr); | ||
#endif | ||
} | ||
|
||
#ifdef _DEBUG | ||
if (!HasAddressAccess<SH_MEM_READ>(addr)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Safety is preferred, but I'm not sure this is necessary in either context. Address should be "trusted", and this can be a very hot path. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I put the debug build into safe operation, because direct memory take a long time with many calls. I can make a cache for quick ranges checks of allowed memory |
||
{ | ||
return pContext->ThrowNativeError("Invalid address access by 0x%x to read memory (base is 0x%x, offset is 0x%x, read block size is %d)", addr, caddr, coffset, sizeof(T)); | ||
} | ||
#endif | ||
|
||
// If you have crash, enable _DEBUG for profiling which plugin the address is not valid. | ||
return (cell_t)*reinterpret_cast<T *>(addr); | ||
} | ||
|
||
template <typename T> | ||
static inline cell_t WriteSecureAddressCell(IPluginContext *pContext, cell_t caddr, cell_t coffset, cell_t cvalue) | ||
{ | ||
void *addr = GetAddress(caddr, coffset); | ||
|
||
if (!IsAddressValidRange(addr)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why isn't this patching memory pages like in the old implementation? |
||
{ | ||
#ifdef _DEBUG | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same printing comment |
||
return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory (base is 0x%x, offset is 0x%x, read block size is %d)", addr, caddr, coffset, sizeof(T)); | ||
#else | ||
return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory", addr); | ||
#endif | ||
} | ||
|
||
#ifdef _DEBUG | ||
if (!HasAddressAccess<SH_MEM_READ /* Old value is being read */ | SH_MEM_WRITE>(addr)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. write the page bits regardless. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
From a viewpoint of dynamic memory hierarchy and a native call cost, it would be advantageous of speed and functionality to read a old value, returning it, instead of void (zero) |
||
{ | ||
return pContext->ThrowNativeError("Invalid address access by 0x%x to write memory (base is 0x%x, offset is 0x%x, read block size is %d)", addr, caddr, coffset, sizeof(T)); | ||
} | ||
#endif | ||
|
||
// If you have crash, enable _DEBUG for profiling which plugin the address is not valid. | ||
cell_t old_cvalue = (cell_t)*reinterpret_cast<T *>(addr); | ||
|
||
*reinterpret_cast<T *>(addr) = (T)cvalue; | ||
|
||
return old_cvalue; | ||
} | ||
|
||
static inline int GetSecureAddressAccessCell(IPluginContext *pContext, cell_t caddr, cell_t coffset) | ||
{ | ||
return GetAddressAccess(GetAddress(caddr, coffset)); | ||
} | ||
|
||
static inline cell_t SetSecureAddressAccessCell(IPluginContext *pContext, cell_t caddr, cell_t coffset, cell_t size, cell_t access) | ||
{ | ||
return (cell_t)SetAddressAccess(GetAddress(caddr, coffset), (size_t)size, (int)access); | ||
} | ||
|
||
static cell_t Address_ReadInt8(IPluginContext *pContext, const cell_t *params) | ||
{ | ||
return ReadSecureAddressCell<uint8_t>(pContext, params[1], params[2]); | ||
} | ||
|
||
static cell_t Address_ReadInt16(IPluginContext *pContext, const cell_t *params) | ||
{ | ||
return ReadSecureAddressCell<uint16_t>(pContext, params[1], params[2]); | ||
} | ||
|
||
static cell_t Address_ReadInt32(IPluginContext *pContext, const cell_t *params) | ||
{ | ||
return ReadSecureAddressCell<uint32_t>(pContext, params[1], params[2]); | ||
} | ||
|
||
static cell_t Address_WriteInt8(IPluginContext *pContext, const cell_t *params) | ||
{ | ||
return WriteSecureAddressCell<uint8_t>(pContext, params[1], params[3], params[2]); | ||
} | ||
|
||
static cell_t Address_WriteInt16(IPluginContext *pContext, const cell_t *params) | ||
{ | ||
return WriteSecureAddressCell<uint16_t>(pContext, params[1], params[3], params[2]); | ||
} | ||
|
||
static cell_t Address_WriteInt32(IPluginContext *pContext, const cell_t *params) | ||
{ | ||
return WriteSecureAddressCell<uint32_t>(pContext, params[1], params[3], params[2]); | ||
} | ||
|
||
static cell_t Address_GetAccess(IPluginContext *pContext, const cell_t *params) | ||
{ | ||
return (cell_t)GetSecureAddressAccessCell(pContext, params[1], params[2]); | ||
} | ||
|
||
static cell_t Address_SetAccess(IPluginContext *pContext, const cell_t *params) | ||
{ | ||
return SetSecureAddressAccessCell(pContext, params[1], params[4], params[3], params[2]); | ||
} | ||
|
||
static cell_t LoadFromAddress(IPluginContext *pContext, const cell_t *params) | ||
{ | ||
#ifdef PLATFORM_X86 | ||
|
@@ -1114,6 +1251,15 @@ REGISTER_NATIVES(coreNatives) | |
{"IsNullVector", IsNullVector}, | ||
{"IsNullString", IsNullString}, | ||
{"LogStackTrace", LogStackTrace}, | ||
|
||
{"Address.ReadInt8", Address_ReadInt8}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the existing natives should be updated to use the new functions. |
||
{"Address.ReadInt16", Address_ReadInt16}, | ||
{"Address.ReadInt32", Address_ReadInt32}, | ||
{"Address.WriteInt8", Address_WriteInt8}, | ||
{"Address.WriteInt16", Address_WriteInt16}, | ||
{"Address.WriteInt32", Address_WriteInt32}, | ||
{"Address.GetAccess", Address_GetAccess}, | ||
{"Address.SetAccess", Address_SetAccess}, | ||
|
||
{"FrameIterator.FrameIterator", FrameIterator_Create}, | ||
{"FrameIterator.Next", FrameIterator_Next}, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -697,6 +697,10 @@ native FeatureStatus GetFeatureStatus(FeatureType type, const char[] name); | |
native void RequireFeature(FeatureType type, const char[] name, | ||
const char[] fmt="", any ...); | ||
|
||
#define SH_MEM_READ (1 << 0) // Memory block can be read. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These are implementation specific, and likely shouldn't have the SourceHook prefix. Changing them to something on the address map would likely be better. |
||
#define SH_MEM_WRITE (1 << 1) // Memory block can be write. | ||
#define SH_MEM_EXEC (1 << 2) // Memory block can be execute. Usually the bytecode to be executed by CPU. | ||
|
||
/** | ||
* Represents how many bytes we can read from an address with one load | ||
*/ | ||
|
@@ -712,6 +716,69 @@ enum Address | |
Address_Null = 0 // a typical invalid result when an address lookup fails | ||
}; | ||
|
||
methodmap Address | ||
{ | ||
// Reads 1 byte from a memory address. | ||
// | ||
// @param offset Offset from the base address (in bytes). | ||
// @return The value that is stored. | ||
// @error Address is null or pointing to reserved memory. | ||
public native any ReadInt8(int offset = 0); | ||
|
||
// Reads 2 bytes from a memory address. | ||
// | ||
// @param offset Offset from the base address (in bytes). | ||
// @return The value that is stored. | ||
// @error Address is null or pointing to reserved memory. | ||
public native any ReadInt16(int offset = 0); | ||
|
||
// Reads 4 bytes from a memory address. | ||
// | ||
// @param offset Offset from the base address (in bytes). | ||
// @return The value that is stored. | ||
// @error Address is null or pointing to reserved memory. | ||
public native any ReadInt32(int offset = 0); | ||
|
||
// Writes 1 byte to a memory address. | ||
// | ||
// @param data Value to store at the address. | ||
// @param offset Offset from the base address (in bytes). | ||
// @return The old value that was stored. | ||
// @error Address is null or pointing to reserved memory. | ||
public native any WriteInt8(any data, int offset = 0); | ||
|
||
// Writes 2 bytes to a memory address. | ||
// | ||
// @param data Value to store at the address. | ||
// @param offset Offset from the base address (in bytes). | ||
// @return The old value that was stored. | ||
// @error Address is null or pointing to reserved memory. | ||
public native any WriteInt16(any data, int offset = 0); | ||
|
||
// Writes 4 bytes to a memory address. | ||
// | ||
// @param data Value to store at the address. | ||
// @param offset Offset from the base address (in bytes). | ||
// @return The old value that was stored. | ||
// @error Address is null or pointing to reserved memory. | ||
public native any WriteInt32(any data, int offset = 0); | ||
|
||
// Gets accesses from a memory address block. | ||
// | ||
// @param offset Offset from the base address (in bytes). | ||
// @return Access flags. See SH_MEM_* for details. | ||
public native int GetAccess(int offset = 0); | ||
|
||
// Sets access flags to a memory address. | ||
// Very effectively with setting accesses for large memory block. | ||
// | ||
// @param access Access flags. See SH_MEM_* for details. | ||
// @param size Memory block size to set accesses. | ||
// @param offset Offset from the base address (in bytes). | ||
// @return If true, accesses have been protected, otherwise failure. | ||
public native bool SetAccess(int access, int size = 4, int offset = 0); | ||
}; | ||
|
||
/** | ||
* Load up to 4 bytes from a memory address. | ||
* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be printed regardless. What's the harm?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An ordinary server holder will be scared.
And from a SourceMod, there are usually not so many error written in message.