├── copying ├── readme.md └── prof.c /copying: -------------------------------------------------------------------------------- 1 | byond-tracy 2 | Copyright (c) 2022, anon 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | LZ4 Library 26 | Copyright (c) 2011-2020, Yann Collet 27 | All rights reserved. 28 | 29 | Redistribution and use in source and binary forms, with or without modification, 30 | are permitted provided that the following conditions are met: 31 | 32 | * Redistributions of source code must retain the above copyright notice, this 33 | list of conditions and the following disclaimer. 34 | 35 | * Redistributions in binary form must reproduce the above copyright notice, this 36 | list of conditions and the following disclaimer in the documentation and/or 37 | other materials provided with the distribution. 38 | 39 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 40 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 41 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 42 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 43 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 44 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 45 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 46 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 47 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 48 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 49 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## byond-tracy 2 | byond-tracy glues together a byond server with the tracy profiler allowing you to analyze and visualize proc calls 3 | 4 | ## supported byond versions 5 | | windows | linux | 6 | | -------- | -------- | 7 | | 515.1647 | 515.1647 | 8 | | 515.1646 | 515.1646 | 9 | | 515.1645 | 515.1645 | 10 | | 515.1644 | 515.1644 | 11 | | 515.1643 | 515.1643 | 12 | | 515.1642 | 515.1642 | 13 | | 515.1641 | 515.1641 | 14 | | 515.1640 | 515.1640 | 15 | | 515.1639 | 515.1639 | 16 | | 515.1638 | 515.1638 | 17 | | 515.1637 | 515.1637 | 18 | | 515.1636 | 515.1636 | 19 | | 515.1635 | 515.1635 | 20 | | 515.1634 | 515.1634 | 21 | | 515.1633 | 515.1633 | 22 | | 515.1632 | 515.1632 | 23 | | 515.1631 | 515.1631 | 24 | | 515.1630 | 515.1630 | 25 | | 515.1627 | 515.1627 | 26 | | 515.1626 | 515.1626 | 27 | | 515.1625 | 515.1625 | 28 | | 515.1624 | 515.1624 | 29 | | 515.1623 | 515.1623 | 30 | | 515.1622 | 515.1622 | 31 | | 515.1621 | 515.1621 | 32 | | 515.1620 | 515.1620 | 33 | | 515.1619 | 515.1619 | 34 | | 515.1618 | 515.1618 | 35 | | 515.1617 | 515.1617 | 36 | | 515.1616 | 515.1616 | 37 | | 515.1615 | 515.1615 | 38 | | 515.1614 | 515.1614 | 39 | | 515.1613 | 515.1613 | 40 | | 515.1612 | | 41 | | 515.1611 | 515.1611 | 42 | | 515.1610 | 515.1610 | 43 | | 515.1609 | 515.1609 | 44 | | 515.1608 | 515.1608 | 45 | | 515.1607 | 515.1607 | 46 | | 515.1606 | 515.1606 | 47 | | 515.1605 | 515.1605 | 48 | | 515.1604 | 515.1604 | 49 | | 515.1603 | 515.1603 | 50 | | 515.1602 | 515.1602 | 51 | | 515.1601 | 515.1601 | 52 | | 515.1600 | 515.1600 | 53 | | 515.1599 | 515.1599 | 54 | | 515.1598 | 515.1598 | 55 | | 515.1597 | 515.1597 | 56 | | 515.1596 | 515.1596 | 57 | | 515.1595 | 515.1595 | 58 | | 515.1594 | 515.1594 | 59 | | 515.1593 | 515.1593 | 60 | | 515.1592 | 515.1592 | 61 | | 515.1591 | 515.1591 | 62 | | 515.1590 | 515.1590 | 63 | | 514.* | 514.* | 64 | 65 | ## supported tracy versions 66 | `0.8.1` `0.8.2` `0.9.0` `0.9.1` `0.10.0` `0.11.0` `0.11.1` 67 | 68 | ## usage 69 | simply call `init` from `prof.dll` to begin collecting profile data and connect using [tracy-server](https://github.com/wolfpld/tracy/releases) `Tracy.exe` 70 | ```dm 71 | /proc/prof_init() 72 | var/lib 73 | 74 | switch(world.system_type) 75 | if(MS_WINDOWS) lib = "prof.dll" 76 | if(UNIX) lib = "libprof.so" 77 | else CRASH("unsupported platform") 78 | 79 | var/init = call_ext(lib, "init")() 80 | if("0" != init) CRASH("[lib] init error: [init]") 81 | 82 | /world/New() 83 | prof_init() 84 | . = ..() 85 | ``` 86 | 87 | ## env vars 88 | set these env vars before launching dreamdaemon to control which node and service to bind 89 | ```console 90 | UTRACY_BIND_ADDRESS 91 | ``` 92 | 93 | ```console 94 | UTRACY_BIND_PORT 95 | ``` 96 | 97 | ## building 98 | no build system included, simply invoke your preferred c11 compiler. 99 | examples: 100 | ```console 101 | cl.exe /nologo /std:c11 /O2 /LD /DNDEBUG prof.c ws2_32.lib /Fe:prof.dll 102 | ``` 103 | 104 | ```console 105 | clang.exe -std=c11 -m32 -shared -Ofast3 -DNDEBUG -fuse-ld=lld-link prof.c -lws2_32 -o prof.dll 106 | ``` 107 | 108 | ```console 109 | gcc -std=c11 -m32 -shared -fPIC -Ofast -s -DNDEBUG prof.c -pthread -o libprof.so 110 | ``` 111 | 112 | ## remarks 113 | byond-tracy is in its infancy and is not production ready for live servers. 114 | -------------------------------------------------------------------------------- /prof.c: -------------------------------------------------------------------------------- 1 | /* c11 minimum */ 2 | #if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 201112L) 3 | # pragma message("minimum supported c standard is c11") 4 | #endif 5 | 6 | #if defined(__cplusplus) 7 | # pragma message("compiling as c++ is ill-advised") 8 | #endif 9 | 10 | /* platform identification */ 11 | #if defined(_WIN32) 12 | # define UTRACY_WINDOWS 13 | # if defined(_WIN64) 14 | # error 64 bit not supported 15 | # endif 16 | # if !defined(_WIN32_WINNT) 17 | # define _WIN32_WINNT 0x0601 18 | # endif 19 | # if !defined(WINVER) 20 | # define WINVER 0x0601 21 | # endif 22 | #elif defined(__linux__) 23 | # define UTRACY_LINUX 24 | # if defined(__x86_64__) 25 | # error 64 bit not supported 26 | # endif 27 | #else 28 | # error platform not detected 29 | #endif 30 | 31 | /* compiler identification */ 32 | #if defined(__clang__) 33 | # define UTRACY_CLANG 34 | #elif defined(__GNUC__) 35 | # define UTRACY_GCC 36 | #elif defined(_MSC_VER) 37 | # define UTRACY_MSVC 38 | #else 39 | # error compiler not detected 40 | #endif 41 | 42 | #if defined(UTRACY_CLANG) || defined(UTRACY_GCC) 43 | # define likely(expr) __builtin_expect(((expr) != 0), 1) 44 | # define unlikely(expr) __builtin_expect(((expr) != 0), 0) 45 | #else 46 | # define likely(expr) (expr) 47 | # define unlikely(expr) (expr) 48 | #endif 49 | #define UTRACY_ALIGN_DOWN(ptr, size) ((void *) ((uintptr_t) (ptr) & (~((size) - 1)))) 50 | 51 | /* data type size check */ 52 | _Static_assert(sizeof(void *) == 4, "incorrect size"); 53 | _Static_assert(sizeof(int) == 4, "incorrect size"); 54 | _Static_assert(sizeof(long long) == 8, "incorrect size"); 55 | 56 | /* linkage and exports */ 57 | #if defined(UTRACY_WINDOWS) 58 | # if defined(UTRACY_CLANG) || defined(UTRACY_GCC) 59 | # define UTRACY_INTERNAL static 60 | # define UTRACY_EXTERNAL __attribute__((visibility("default"))) __attribute__((dllexport)) 61 | # define UTRACY_INLINE inline __attribute__((always_inline)) 62 | # elif defined(UTRACY_MSVC) 63 | # define UTRACY_INTERNAL static 64 | # define UTRACY_EXTERNAL __declspec(dllexport) 65 | # define UTRACY_INLINE inline __forceinline 66 | # endif 67 | #elif defined(UTRACY_LINUX) 68 | # if defined(UTRACY_CLANG) || defined(UTRACY_GCC) 69 | # define UTRACY_INTERNAL static 70 | # define UTRACY_EXTERNAL __attribute__((visibility("default"))) 71 | # define UTRACY_INLINE inline __attribute__((always_inline)) 72 | # endif 73 | #endif 74 | 75 | /* calling conventions */ 76 | #if defined(UTRACY_WINDOWS) 77 | # define UTRACY_WINDOWS_CDECL __cdecl 78 | # define UTRACY_WINDOWS_STDCALL __stdcall 79 | # define UTRACY_WINDOWS_THISCALL __thiscall 80 | # define UTRACY_LINUX_CDECL 81 | # define UTRACY_LINUX_STDCALL 82 | # define UTRACY_LINUX_THISCALL 83 | # define UTRACY_LINUX_REGPARM(a) 84 | #elif defined(UTRACY_LINUX) 85 | # define UTRACY_WINDOWS_CDECL 86 | # define UTRACY_WINDOWS_STDCALL 87 | # define UTRACY_WINDOWS_THISCALL 88 | # define UTRACY_LINUX_CDECL __attribute__((cdecl)) 89 | # define UTRACY_LINUX_STDCALL __attribute__((stdcall)) 90 | # define UTRACY_LINUX_THISCALL __attribute__((thiscall)) 91 | # define UTRACY_LINUX_REGPARM(a) __attribute__((regparm(a))) 92 | #endif 93 | 94 | /* headers */ 95 | #if defined(UTRACY_WINDOWS) 96 | # define NOMINMAX 97 | # include 98 | # include 99 | # include 100 | #elif defined(UTRACY_LINUX) 101 | # define _GNU_SOURCE 102 | # include 103 | # include 104 | # include 105 | # include 106 | # include 107 | # include 108 | # include 109 | # include 110 | # include 111 | # include 112 | # include 113 | # include 114 | # include 115 | # include 116 | /* avoid including stdlib.h */ 117 | char *getenv(char const *); 118 | #endif 119 | 120 | #include 121 | #include 122 | 123 | #if (__STDC_HOSTED__ == 1) 124 | # include 125 | # include 126 | #endif 127 | 128 | #if !defined(__STDC_NO_ATOMICS__) 129 | # include 130 | #endif 131 | 132 | #if (__STDC_HOSTED__ == 0) 133 | void *memset(void *const a, int value, size_t len) { 134 | for(size_t i=0; i _b ? _a : _b; \ 175 | }) 176 | #elif defined(UTRACY_MSVC) 177 | # define max(a, b) (((a) > (b)) ? (a) : (b)) 178 | #endif 179 | 180 | #if defined(min) 181 | # undef min 182 | #endif 183 | #if defined(UTRACY_CLANG) || defined(UTRACY_GCC) 184 | # define min(a, b) ({ \ 185 | __typeof__(a) _a = (a); \ 186 | __typeof__(b) _b = (b); \ 187 | _a < _b ? _a : _b; \ 188 | }) 189 | #elif defined(UTRACY_MSVC) 190 | # define min(a, b) (((a) < (b)) ? (a) : (b)) 191 | #endif 192 | 193 | #if defined(UTRACY_CLANG) || defined(UTRACY_GCC) 194 | # if __has_builtin(__builtin_memcpy) 195 | # define UTRACY_MEMCPY __builtin_memcpy 196 | # else 197 | # define UTRACY_MEMCPY memcpy 198 | # endif 199 | # if __has_builtin(__builtin_memset) 200 | # define UTRACY_MEMSET __builtin_memset 201 | # else 202 | # define UTRACY_MEMSET memset 203 | # endif 204 | # if __has_builtin(__builtin_memcmp) 205 | # define UTRACY_MEMCMP __builtin_memcmp 206 | # else 207 | # define UTRACY_MEMCMP memcmp 208 | # endif 209 | #else 210 | # define UTRACY_MEMCPY memcpy 211 | # define UTRACY_MEMSET memset 212 | # define UTRACY_MEMCMP memcmp 213 | #endif 214 | 215 | 216 | /* debugging */ 217 | #if defined(UTRACY_DEBUG) || defined(DEBUG) 218 | # include 219 | # define LOG_DEBUG_ERROR fprintf(stderr, "err: %s %s:%d\n", __func__, __FILE__, __LINE__) 220 | # define LOG_INFO(...) fprintf(stdout, __VA_ARGS__) 221 | #else 222 | # define LOG_DEBUG_ERROR 223 | # define LOG_INFO(...) 224 | #endif 225 | 226 | /* config */ 227 | #define UTRACY_L1_LINE_SIZE (64) 228 | #define UTRACY_PAGE_SIZE (4096) 229 | 230 | #define EVENT_QUEUE_CAPACITY (1u << 18u) 231 | _Static_assert((EVENT_QUEUE_CAPACITY & (EVENT_QUEUE_CAPACITY - 1)) == 0, "EVENT_QUEUE_CAPACITY must be a power of 2"); 232 | #define UTRACY_LATENCY (100000000ll) 233 | #define UTRACY_MAX_FRAME_SIZE (256u * 1024u) 234 | 235 | /* byond types */ 236 | struct object { 237 | union { 238 | int unsigned padding; 239 | char unsigned type; 240 | }; 241 | union { 242 | int unsigned i; 243 | float f; 244 | }; 245 | }; 246 | 247 | struct string { 248 | char *data; 249 | int unsigned id; 250 | struct string *left; 251 | struct string *right; 252 | int unsigned refcount; 253 | int unsigned unk0; 254 | int unsigned len; 255 | }; 256 | 257 | struct procdef { 258 | int unsigned path; 259 | int unsigned name; 260 | int unsigned desc; 261 | int unsigned category; 262 | int unsigned flags; 263 | int unsigned unk0; 264 | int unsigned bytecode; 265 | int unsigned locals; 266 | int unsigned parameters; 267 | }; 268 | 269 | struct misc { 270 | struct { 271 | short unsigned len; 272 | int unsigned unk0; 273 | int unsigned *bytecode; 274 | } bytecode; 275 | struct { 276 | short unsigned len; 277 | int unsigned unk0; 278 | int unsigned *locals; 279 | } locals; 280 | struct { 281 | short unsigned len; 282 | int unsigned unk0; 283 | int unsigned *params; 284 | } params; 285 | }; 286 | 287 | struct proc { 288 | int unsigned procdef; 289 | char unsigned flags; 290 | char unsigned supers; 291 | short unsigned unused; 292 | struct object usr; 293 | struct object src; 294 | struct execution_context *ctx; 295 | int unsigned sequence; 296 | void (*callback)(struct object, int unsigned); 297 | int unsigned callback_arg; 298 | int unsigned argc; 299 | struct object *argv; 300 | int unsigned unk0; 301 | }; 302 | 303 | /* byond type size check */ 304 | _Static_assert(sizeof(struct object) == 8, "incorrect size"); 305 | _Static_assert(sizeof(struct string) == 28, "incorrect size"); 306 | _Static_assert(sizeof(struct procdef) >= 4, "incorrect size"); 307 | _Static_assert(sizeof(struct misc) == 36, "incorrect size"); 308 | _Static_assert(sizeof(struct proc) >= 4, "incorrect size"); 309 | 310 | /* 311 | * LZ4 - Fast LZ compression algorithm 312 | * Header File 313 | * Copyright (C) 2011-2020, Yann Collet. 314 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 315 | Redistribution and use in source and binary forms, with or without 316 | modification, are permitted provided that the following conditions are 317 | met: 318 | * Redistributions of source code must retain the above copyright 319 | notice, this list of conditions and the following disclaimer. 320 | * Redistributions in binary form must reproduce the above 321 | copyright notice, this list of conditions and the following disclaimer 322 | in the documentation and/or other materials provided with the 323 | distribution. 324 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 325 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 326 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 327 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 328 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 329 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 330 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 331 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 333 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 334 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 335 | You can contact the author at : 336 | - LZ4 homepage : http://www.lz4.org 337 | - LZ4 source repository : https://github.com/lz4/lz4 338 | */ 339 | 340 | #define LZ4_MEMORY_USAGE_MIN 10 341 | //#define LZ4_MEMORY_USAGE_DEFAULT 14 342 | #define LZ4_MEMORY_USAGE_DEFAULT 20 343 | #define LZ4_MEMORY_USAGE_MAX 20 344 | 345 | #if !defined(LZ4_MEMORY_USAGE) 346 | # define LZ4_MEMORY_USAGE LZ4_MEMORY_USAGE_DEFAULT 347 | #endif 348 | 349 | #if (LZ4_MEMORY_USAGE < LZ4_MEMORY_USAGE_MIN) 350 | # error "LZ4_MEMORY_USAGE is too small !" 351 | #endif 352 | 353 | #if (LZ4_MEMORY_USAGE > LZ4_MEMORY_USAGE_MAX) 354 | # error "LZ4_MEMORY_USAGE is too large !" 355 | #endif 356 | 357 | #define LZ4_MAX_INPUT_SIZE 0x7E000000 358 | #define LZ4_COMPRESSBOUND(isize) ((unsigned) (isize) > (unsigned) LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize) / 255) + 16) 359 | #define LZ4_ACCELERATION_DEFAULT 1 360 | #define LZ4_ACCELERATION_MAX 65537 361 | 362 | #if !defined(LZ4_DISTANCE_MAX) 363 | # define LZ4_DISTANCE_MAX 65535 364 | #endif 365 | #define LZ4_DISTANCE_ABSOLUTE_MAX 65535 366 | #if (LZ4_DISTANCE_MAX > LZ4_DISTANCE_ABSOLUTE_MAX) 367 | # error "LZ4_DISTANCE_MAX is too big : must be <= 65535" 368 | #endif 369 | 370 | #define ML_BITS 4u 371 | #define ML_MASK ((1U << ML_BITS) - 1u) 372 | #define RUN_BITS (8u - ML_BITS) 373 | #define RUN_MASK ((1U << RUN_BITS) - 1u) 374 | 375 | #define MINMATCH 4 376 | #define WILDCOPYLENGTH 8 377 | #define LASTLITERALS 5 378 | #define MFLIMIT 12 379 | #define MATCH_SAFEGUARD_DISTANCE ((2 * WILDCOPYLENGTH) - MINMATCH) 380 | #define FASTLOOP_SAFE_DISTANCE 64 381 | #define LZ4_minLength (MFLIMIT + 1) 382 | 383 | #define LZ4_64Klimit (65536 + (MFLIMIT - 1)) 384 | #define LZ4_skipTrigger ((LZ4_u32) 6u) 385 | 386 | #define LZ4_HASHLOG (LZ4_MEMORY_USAGE - 2) 387 | #define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) 388 | #define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) 389 | 390 | #define LZ4_STREAMSIZE ((1ul << LZ4_MEMORY_USAGE) + 32u) 391 | #define LZ4_STREAMSIZE_VOIDP (LZ4_STREAMSIZE / sizeof(void *)) 392 | 393 | #define LZ4_STATIC_ASSERT(a) _Static_assert((a), "") 394 | 395 | typedef char signed LZ4_i8; 396 | typedef char unsigned LZ4_byte; 397 | typedef short unsigned LZ4_u16; 398 | typedef int unsigned LZ4_u32; 399 | typedef long long unsigned LZ4_u64; 400 | typedef union LZ4_stream_u LZ4_stream_t; 401 | typedef struct LZ4_stream_t_internal LZ4_stream_t_internal; 402 | typedef size_t reg_t; 403 | 404 | typedef enum { 405 | LZ4_clearedTable = 0, 406 | LZ4_byPtr, 407 | LZ4_byU32, 408 | LZ4_byU16 409 | } LZ4_tableType_t; 410 | 411 | typedef enum { 412 | LZ4_notLimited = 0, 413 | LZ4_limitedOutput = 1, 414 | LZ4_fillOutput = 2 415 | } LZ4_limitedOutput_directive; 416 | 417 | typedef enum { 418 | LZ4_noDict = 0, 419 | LZ4_withPrefix64k, 420 | LZ4_usingExtDict, 421 | LZ4_usingDictCtx 422 | } LZ4_dict_directive; 423 | 424 | typedef enum { 425 | LZ4_noDictIssue = 0, 426 | LZ4_dictSmall 427 | } LZ4_dictIssue_directive; 428 | 429 | struct LZ4_stream_t_internal { 430 | LZ4_u32 hashTable[LZ4_HASH_SIZE_U32]; 431 | LZ4_u32 currentOffset; 432 | LZ4_u32 tableType; 433 | LZ4_byte const *dictionary; 434 | LZ4_stream_t_internal const *dictCtx; 435 | LZ4_u32 dictSize; 436 | }; 437 | 438 | union LZ4_stream_u { 439 | void *table[LZ4_STREAMSIZE_VOIDP]; 440 | LZ4_stream_t_internal internal_donotuse; 441 | }; 442 | 443 | #pragma pack(push, 1) 444 | typedef union { 445 | LZ4_u16 u16; 446 | LZ4_u32 u32; 447 | reg_t uArch; 448 | } LZ4_unalign; 449 | #pragma pack(pop) 450 | 451 | UTRACY_INTERNAL UTRACY_INLINE 452 | LZ4_u16 LZ4_read16(void const *ptr) { 453 | return ((LZ4_unalign const *) ptr)->u16; 454 | } 455 | 456 | UTRACY_INTERNAL UTRACY_INLINE 457 | LZ4_u32 LZ4_read32(void const *ptr) { 458 | return ((LZ4_unalign const *) ptr)->u32; 459 | } 460 | 461 | UTRACY_INTERNAL UTRACY_INLINE 462 | reg_t LZ4_read_ARCH(void const *ptr) { 463 | return ((LZ4_unalign const *) ptr)->uArch; 464 | } 465 | 466 | UTRACY_INTERNAL UTRACY_INLINE 467 | void LZ4_write16(void *memPtr, LZ4_u16 value) { 468 | ((LZ4_unalign *) memPtr)->u16 = value; 469 | } 470 | 471 | UTRACY_INTERNAL UTRACY_INLINE 472 | void LZ4_write32(void *memPtr, LZ4_u32 value) { 473 | ((LZ4_unalign *) memPtr)->u32 = value; 474 | } 475 | 476 | #define LZ4_writeLE16 LZ4_write16 477 | 478 | UTRACY_INTERNAL UTRACY_INLINE 479 | void LZ4_wildCopy8(void *dstPtr, const void *srcPtr, void *dstEnd) { 480 | LZ4_byte *d = (LZ4_byte *) dstPtr; 481 | LZ4_byte const *s = (LZ4_byte const *) srcPtr; 482 | LZ4_byte *const e = (LZ4_byte *) dstEnd; 483 | 484 | do { 485 | (void) UTRACY_MEMCPY(d, s, 8); 486 | d += 8; 487 | s += 8; 488 | } while (d < e); 489 | } 490 | 491 | UTRACY_INTERNAL UTRACY_INLINE 492 | unsigned LZ4_NbCommonBytes(reg_t val) { 493 | assert(val != 0); 494 | 495 | #if defined(UTRACY_MSVC) 496 | long unsigned r; 497 | _BitScanForward(&r, (LZ4_u32) val); 498 | return (unsigned) r >> 3u; 499 | 500 | #elif __has_builtin(__builtin_ctx) 501 | return (unsigned) __builtin_ctz((LZ4_u32) val) >> 3u; 502 | 503 | #else 504 | LZ4_u32 const m = 0x01010101u; 505 | return (unsigned) ((((val - 1) ^ val) & (m - 1)) * m) >> 24u; 506 | 507 | #endif 508 | } 509 | 510 | UTRACY_INTERNAL UTRACY_INLINE 511 | unsigned LZ4_count(LZ4_byte const *pIn, LZ4_byte const *pMatch, LZ4_byte const *pInLimit) { 512 | LZ4_byte const *const pStart = pIn; 513 | 514 | if(likely(pIn < pInLimit - (sizeof(reg_t) - 1))) { 515 | reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); 516 | if(!diff) { 517 | pIn += sizeof(reg_t); 518 | pMatch += sizeof(reg_t); 519 | } else { 520 | return LZ4_NbCommonBytes(diff); 521 | } 522 | } 523 | 524 | while(likely(pIn < pInLimit - (sizeof(reg_t) - 1))) { 525 | reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); 526 | if(!diff) { 527 | pIn += sizeof(reg_t); 528 | pMatch += sizeof(reg_t); 529 | continue; 530 | } 531 | pIn += LZ4_NbCommonBytes(diff); 532 | return (unsigned) (pIn - pStart); 533 | } 534 | 535 | if((sizeof(reg_t) == 8) && (pIn < (pInLimit - 3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { 536 | pIn += 4; 537 | pMatch += 4; 538 | } 539 | 540 | if((pIn < (pInLimit - 1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { 541 | pIn += 2; 542 | pMatch += 2; 543 | } 544 | 545 | if((pIn < pInLimit) && (*pMatch == *pIn)) { 546 | pIn++; 547 | } 548 | 549 | return (unsigned)(pIn - pStart); 550 | } 551 | 552 | 553 | UTRACY_INTERNAL UTRACY_INLINE 554 | LZ4_u32 LZ4_hash4(LZ4_u32 sequence, LZ4_tableType_t const tableType) { 555 | if(tableType == LZ4_byU16) { 556 | return ((sequence * 2654435761u) >> ((MINMATCH * 8) - (LZ4_HASHLOG + 1))); 557 | } else { 558 | return ((sequence * 2654435761u) >> ((MINMATCH * 8) - LZ4_HASHLOG)); 559 | } 560 | } 561 | 562 | UTRACY_INTERNAL UTRACY_INLINE 563 | LZ4_u32 LZ4_hash5(LZ4_u64 sequence, LZ4_tableType_t const tableType) { 564 | LZ4_u32 const hashLog = (tableType == LZ4_byU16) ? LZ4_HASHLOG + 1 : LZ4_HASHLOG; 565 | LZ4_u64 const prime5bytes = 889523592379llu; 566 | return (LZ4_u32) (((sequence << 24) * prime5bytes) >> (64 - hashLog)); 567 | } 568 | 569 | UTRACY_INTERNAL UTRACY_INLINE 570 | LZ4_u32 LZ4_hashPosition(void const *const p, LZ4_tableType_t const tableType) { 571 | if((sizeof(reg_t) == 8) && (tableType != LZ4_byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); 572 | return LZ4_hash4(LZ4_read32(p), tableType); 573 | } 574 | 575 | UTRACY_INTERNAL UTRACY_INLINE 576 | void LZ4_clearHash(LZ4_u32 h, void *tableBase, LZ4_tableType_t const tableType) { 577 | switch(tableType) { 578 | default: 579 | case LZ4_clearedTable: {assert(0); return;} 580 | case LZ4_byPtr: {LZ4_byte const **hashTable = (LZ4_byte const **) tableBase; hashTable[h] = NULL; return;} 581 | case LZ4_byU32: {LZ4_u32 *hashTable = (LZ4_u32 *) tableBase; hashTable[h] = 0; return;} 582 | case LZ4_byU16: {LZ4_u16 *hashTable = (LZ4_u16 *) tableBase; hashTable[h] = 0; return;} 583 | } 584 | } 585 | 586 | UTRACY_INTERNAL UTRACY_INLINE 587 | void LZ4_putIndexOnHash(LZ4_u32 idx, LZ4_u32 h, void *tableBase, LZ4_tableType_t const tableType) { 588 | switch(tableType) { 589 | default: 590 | case LZ4_clearedTable: 591 | case LZ4_byPtr: {assert(0); return;} 592 | case LZ4_byU32: {LZ4_u32 *hashTable = (LZ4_u32 *) tableBase; hashTable[h] = idx; return;} 593 | case LZ4_byU16: {LZ4_u16 *hashTable = (LZ4_u16 *) tableBase; assert(idx < 65536u); hashTable[h] = (LZ4_u16) idx; return;} 594 | } 595 | } 596 | 597 | UTRACY_INTERNAL UTRACY_INLINE 598 | void LZ4_putPositionOnHash(LZ4_byte const *p, LZ4_u32 h, void *tableBase, LZ4_tableType_t const tableType, LZ4_byte const *srcBase) { 599 | switch(tableType) { 600 | case LZ4_clearedTable: {assert(0); return;} 601 | case LZ4_byPtr: {LZ4_byte const **hashTable = (LZ4_byte const **) tableBase; hashTable[h] = p; return;} 602 | case LZ4_byU32: {LZ4_u32 *hashTable = (LZ4_u32 *) tableBase; hashTable[h] = (LZ4_u32) (p - srcBase); return;} 603 | case LZ4_byU16: {LZ4_u16 *hashTable = (LZ4_u16 *) tableBase; hashTable[h] = (LZ4_u16) (p - srcBase); return;} 604 | } 605 | } 606 | 607 | UTRACY_INTERNAL UTRACY_INLINE 608 | void LZ4_putPosition(LZ4_byte const *p, void *tableBase, LZ4_tableType_t tableType, LZ4_byte const *srcBase) { 609 | LZ4_u32 const h = LZ4_hashPosition(p, tableType); 610 | LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); 611 | } 612 | 613 | UTRACY_INTERNAL UTRACY_INLINE 614 | LZ4_u32 LZ4_getIndexOnHash(LZ4_u32 h, void const *tableBase, LZ4_tableType_t tableType) { 615 | LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2); 616 | if(tableType == LZ4_byU32) { 617 | const LZ4_u32 *const hashTable = (const LZ4_u32 *) tableBase; 618 | assert(h < (1U << (LZ4_MEMORY_USAGE - 2))); 619 | return hashTable[h]; 620 | } 621 | if(tableType == LZ4_byU16) { 622 | const LZ4_u16 *const hashTable = (const LZ4_u16 *) tableBase; 623 | assert(h < (1U << (LZ4_MEMORY_USAGE - 1))); 624 | return hashTable[h]; 625 | } 626 | assert(0); 627 | return 0; 628 | } 629 | 630 | UTRACY_INTERNAL UTRACY_INLINE 631 | LZ4_byte const *LZ4_getPositionOnHash(LZ4_u32 h, void const *tableBase, LZ4_tableType_t tableType, LZ4_byte const *srcBase) { 632 | if(tableType == LZ4_byPtr) {LZ4_byte const *const *hashTable = (LZ4_byte const *const *) tableBase; return hashTable[h];} 633 | if(tableType == LZ4_byU32) {LZ4_u32 const *const hashTable = (LZ4_u32 const *) tableBase; return hashTable[h] + srcBase;} 634 | { 635 | LZ4_u16 const *const hashTable = (LZ4_u16 const *) tableBase; 636 | return hashTable[h] + srcBase; 637 | } 638 | } 639 | 640 | UTRACY_INTERNAL UTRACY_INLINE 641 | LZ4_byte const *LZ4_getPosition(LZ4_byte const *p, void const *tableBase, LZ4_tableType_t tableType, LZ4_byte const *srcBase) { 642 | LZ4_u32 const h = LZ4_hashPosition(p, tableType); 643 | return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); 644 | } 645 | 646 | UTRACY_INTERNAL UTRACY_INLINE 647 | void LZ4_prepareTable(LZ4_stream_t_internal *const cctx, int const inputSize, LZ4_tableType_t const tableType) { 648 | if((LZ4_tableType_t) cctx->tableType != LZ4_clearedTable) { 649 | assert(inputSize >= 0); 650 | 651 | if( 652 | (LZ4_tableType_t) cctx->tableType != tableType || 653 | ((tableType == LZ4_byU16) && cctx->currentOffset + (unsigned) inputSize >= 0xFFFFU) || 654 | ((tableType == LZ4_byU32) && cctx->currentOffset > 1073741824u) || 655 | tableType == LZ4_byPtr || 656 | inputSize >= 4096 657 | ) { 658 | (void) UTRACY_MEMSET(cctx->hashTable, 0, LZ4_HASHTABLESIZE); 659 | cctx->currentOffset = 0; 660 | cctx->tableType = (LZ4_u32) LZ4_clearedTable; 661 | } 662 | } 663 | 664 | if(cctx->currentOffset != 0 && tableType == LZ4_byU32) { 665 | cctx->currentOffset += 65536u; 666 | } 667 | 668 | cctx->dictCtx = NULL; 669 | cctx->dictionary = NULL; 670 | cctx->dictSize = 0; 671 | } 672 | 673 | UTRACY_INTERNAL UTRACY_INLINE 674 | void LZ4_renormDictT(LZ4_stream_t_internal *LZ4_dict, int nextSize) { 675 | assert(nextSize >= 0); 676 | if(LZ4_dict->currentOffset + (unsigned) nextSize > 0x80000000u) { 677 | LZ4_u32 const delta = LZ4_dict->currentOffset - 65536u; 678 | LZ4_byte const *dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; 679 | for(int i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i] = 0; 681 | else LZ4_dict->hashTable[i] -= delta; 682 | } 683 | 684 | LZ4_dict->currentOffset = 65536u; 685 | if(LZ4_dict->dictSize > 65536u) LZ4_dict->dictSize = 65536u; 686 | LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; 687 | } 688 | } 689 | 690 | UTRACY_INTERNAL UTRACY_INLINE 691 | int LZ4_compress_generic_validated(LZ4_stream_t_internal *const cctx, char const *const source, char *const dest, int const inputSize, int *inputConsumed, int const maxOutputSize, LZ4_limitedOutput_directive const outputDirective, LZ4_tableType_t const tableType, LZ4_dict_directive const dictDirective, LZ4_dictIssue_directive const dictIssue, int const acceleration) { 692 | int result; 693 | LZ4_byte const *ip = (LZ4_byte const *) source; 694 | 695 | LZ4_u32 const startIndex = cctx->currentOffset; 696 | LZ4_byte const *base = (LZ4_byte const *) source - startIndex; 697 | LZ4_byte const *lowLimit; 698 | 699 | LZ4_stream_t_internal const *dictCtx = (LZ4_stream_t_internal const *) cctx->dictCtx; 700 | LZ4_byte const *const dictionary = dictDirective == LZ4_usingDictCtx ? dictCtx->dictionary : cctx->dictionary; 701 | LZ4_u32 const dictSize = dictDirective == LZ4_usingDictCtx ? dictCtx->dictSize : cctx->dictSize; 702 | LZ4_u32 const dictDelta = (dictDirective == LZ4_usingDictCtx) ? startIndex - dictCtx->currentOffset : 0; 703 | 704 | int const maybe_extMem = (dictDirective == LZ4_usingExtDict) || (dictDirective == LZ4_usingDictCtx); 705 | LZ4_u32 const prefixIdxLimit = startIndex - dictSize; 706 | LZ4_byte const *const dictEnd = dictionary ? dictionary + dictSize : dictionary; 707 | LZ4_byte const *anchor = (LZ4_byte const *) source; 708 | LZ4_byte const *const iend = ip + inputSize; 709 | LZ4_byte const *const mflimitPlusOne = iend - MFLIMIT + 1; 710 | LZ4_byte const *const matchlimit = iend - LASTLITERALS; 711 | 712 | LZ4_byte const *dictBase = (dictionary == NULL) ? NULL : (dictDirective == LZ4_usingDictCtx) ? dictionary + dictSize - dictCtx->currentOffset : dictionary + dictSize - startIndex; 713 | 714 | LZ4_byte *op = (LZ4_byte *) dest; 715 | LZ4_byte *const olimit = op + maxOutputSize; 716 | 717 | LZ4_u32 offset = 0; 718 | LZ4_u32 forwardH; 719 | 720 | assert(ip != NULL); 721 | if(outputDirective == LZ4_fillOutput && maxOutputSize < 1) { 722 | return 0; 723 | } 724 | if((tableType == LZ4_byU16) && (inputSize >= LZ4_64Klimit)) { 725 | return 0; 726 | } 727 | if(tableType == LZ4_byPtr) assert(dictDirective == LZ4_noDict); 728 | assert(acceleration >= 1); 729 | 730 | lowLimit = (LZ4_byte const *) source - (dictDirective == LZ4_withPrefix64k ? dictSize : 0); 731 | 732 | if(dictDirective == LZ4_usingDictCtx) { 733 | cctx->dictCtx = NULL; 734 | cctx->dictSize = (LZ4_u32) inputSize; 735 | } else { 736 | cctx->dictSize += (LZ4_u32) inputSize; 737 | } 738 | 739 | cctx->currentOffset += (LZ4_u32) inputSize; 740 | cctx->tableType = (LZ4_u32) tableType; 741 | 742 | if(inputSize < LZ4_minLength) goto _last_literals; 743 | 744 | LZ4_putPosition(ip, cctx->hashTable, tableType, base); 745 | ip++; 746 | forwardH = LZ4_hashPosition(ip, tableType); 747 | 748 | for(;;) { 749 | LZ4_byte const *match; 750 | LZ4_byte *token; 751 | LZ4_byte const *filledIp; 752 | 753 | if(tableType == LZ4_byPtr) { 754 | LZ4_byte const *forwardIp = ip; 755 | int step = 1; 756 | int searchMatchNb = acceleration << LZ4_skipTrigger; 757 | do { 758 | LZ4_u32 const h = forwardH; 759 | ip = forwardIp; 760 | forwardIp += step; 761 | step = (searchMatchNb++ >> LZ4_skipTrigger); 762 | 763 | if(unlikely(forwardIp > mflimitPlusOne)) goto _last_literals; 764 | assert(ip < mflimitPlusOne); 765 | 766 | match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base); 767 | forwardH = LZ4_hashPosition(forwardIp, tableType); 768 | LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base); 769 | 770 | } while((match + LZ4_DISTANCE_MAX < ip) || (LZ4_read32(match) != LZ4_read32(ip))); 771 | 772 | } else { 773 | LZ4_byte const *forwardIp = ip; 774 | int step = 1; 775 | int searchMatchNb = acceleration << LZ4_skipTrigger; 776 | do { 777 | LZ4_u32 const h = forwardH; 778 | LZ4_u32 const current = (LZ4_u32) (forwardIp - base); 779 | LZ4_u32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType); 780 | assert(matchIndex <= current); 781 | assert(forwardIp - base < (ptrdiff_t) (2147483648u - 1u)); 782 | ip = forwardIp; 783 | forwardIp += step; 784 | step = (searchMatchNb++ >> LZ4_skipTrigger); 785 | 786 | if(unlikely(forwardIp > mflimitPlusOne)) goto _last_literals; 787 | assert(ip < mflimitPlusOne); 788 | 789 | if(dictDirective == LZ4_usingDictCtx) { 790 | if(matchIndex < startIndex) { 791 | assert(tableType == LZ4_byU32); 792 | matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, LZ4_byU32); 793 | match = dictBase + matchIndex; 794 | matchIndex += dictDelta; 795 | lowLimit = dictionary; 796 | } else { 797 | match = base + matchIndex; 798 | lowLimit = (LZ4_byte const *) source; 799 | } 800 | } else if(dictDirective == LZ4_usingExtDict) { 801 | if(matchIndex < startIndex) { 802 | assert(startIndex - matchIndex >= MINMATCH); 803 | assert(dictBase); 804 | match = dictBase + matchIndex; 805 | lowLimit = dictionary; 806 | } else { 807 | match = base + matchIndex; 808 | lowLimit = (LZ4_byte const *)source; 809 | } 810 | } else { 811 | match = base + matchIndex; 812 | } 813 | 814 | forwardH = LZ4_hashPosition(forwardIp, tableType); 815 | LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType); 816 | 817 | if((dictIssue == LZ4_dictSmall) && (matchIndex < prefixIdxLimit)) { 818 | continue; 819 | } 820 | 821 | assert(matchIndex < current); 822 | 823 | if(((tableType != LZ4_byU16) || (LZ4_DISTANCE_MAX < LZ4_DISTANCE_ABSOLUTE_MAX)) && (matchIndex + LZ4_DISTANCE_MAX < current)) { 824 | continue; 825 | } 826 | 827 | assert((current - matchIndex) <= LZ4_DISTANCE_MAX); 828 | 829 | if(LZ4_read32(match) == LZ4_read32(ip)) { 830 | if(maybe_extMem) offset = current - matchIndex; 831 | break; 832 | } 833 | 834 | } while(1); 835 | } 836 | 837 | filledIp = ip; 838 | while(((ip > anchor) & (match > lowLimit)) && (unlikely(ip[-1] == match[-1]))) { 839 | ip--; 840 | match--; 841 | } 842 | 843 | { 844 | unsigned const litLength = (unsigned) (ip - anchor); 845 | token = op++; 846 | if((outputDirective == LZ4_limitedOutput) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength / 255) > olimit))) { 847 | return 0; 848 | } 849 | 850 | if((outputDirective == LZ4_fillOutput) && (unlikely(op + (litLength + 240) / 255 + litLength + 2 + 1 + MFLIMIT - MINMATCH > olimit))) { 851 | op--; 852 | goto _last_literals; 853 | } 854 | 855 | if(litLength >= RUN_MASK) { 856 | int len = (int) (litLength - RUN_MASK); 857 | *token = (RUN_MASK << ML_BITS); 858 | for(; len >= 255; len -= 255) *op++ = 255; 859 | *op++ = (LZ4_byte) len; 860 | } else { 861 | *token = (LZ4_byte) (litLength << ML_BITS); 862 | } 863 | 864 | LZ4_wildCopy8(op, anchor, op + litLength); 865 | op += litLength; 866 | } 867 | 868 | _next_match: 869 | if((outputDirective == LZ4_fillOutput) && (op + 2 + 1 + MFLIMIT - MINMATCH > olimit)) { 870 | op = token; 871 | goto _last_literals; 872 | } 873 | 874 | if(maybe_extMem) { 875 | assert(offset <= LZ4_DISTANCE_MAX && offset > 0); 876 | LZ4_writeLE16(op, (LZ4_u16) offset); 877 | op += 2; 878 | } else { 879 | assert(ip - match <= LZ4_DISTANCE_MAX); 880 | LZ4_writeLE16(op, (LZ4_u16) (ip - match)); 881 | op += 2; 882 | } 883 | 884 | { 885 | unsigned matchCode; 886 | 887 | if((dictDirective == LZ4_usingExtDict || dictDirective == LZ4_usingDictCtx) && (lowLimit == dictionary)) { 888 | LZ4_byte const *limit = ip + (dictEnd - match); 889 | assert(dictEnd > match); 890 | if(limit > matchlimit) limit = matchlimit; 891 | matchCode = LZ4_count(ip + MINMATCH, match + MINMATCH, limit); 892 | ip += (size_t) matchCode + MINMATCH; 893 | if(ip == limit) { 894 | unsigned const more = LZ4_count(limit, (LZ4_byte const *) source, matchlimit); 895 | matchCode += more; 896 | ip += more; 897 | } 898 | } else { 899 | matchCode = LZ4_count(ip + MINMATCH, match + MINMATCH, matchlimit); 900 | ip += (size_t) matchCode + MINMATCH; 901 | } 902 | 903 | if((outputDirective) && (unlikely(op + (1 + LASTLITERALS) + (matchCode + 240) / 255 > olimit))) { 904 | if(outputDirective == LZ4_fillOutput) { 905 | LZ4_u32 newMatchCode = 15 - 1 + ((LZ4_u32) (olimit - op) - 1 - LASTLITERALS) * 255; 906 | ip -= matchCode - newMatchCode; 907 | assert(newMatchCode < matchCode); 908 | matchCode = newMatchCode; 909 | if(unlikely(ip <= filledIp)) { 910 | LZ4_byte const *ptr; 911 | for(ptr = ip; ptr <= filledIp; ++ptr) { 912 | LZ4_u32 const h = LZ4_hashPosition(ptr, tableType); 913 | LZ4_clearHash(h, cctx->hashTable, tableType); 914 | } 915 | } 916 | } else { 917 | assert(outputDirective == LZ4_limitedOutput); 918 | return 0; 919 | } 920 | } 921 | 922 | if(matchCode >= ML_MASK) { 923 | *token += ML_MASK; 924 | matchCode -= ML_MASK; 925 | LZ4_write32(op, 0xFFFFFFFFu); 926 | while(matchCode >= 4 * 255) { 927 | op += 4; 928 | LZ4_write32(op, 0xFFFFFFFFu); 929 | matchCode -= 4 * 255; 930 | } 931 | op += matchCode / 255; 932 | *op++ = (LZ4_byte) (matchCode % 255); 933 | } else { 934 | *token += (LZ4_byte)(matchCode); 935 | } 936 | } 937 | 938 | assert(!(outputDirective == LZ4_fillOutput && op + 1 + LASTLITERALS > olimit)); 939 | 940 | anchor = ip; 941 | 942 | if(ip >= mflimitPlusOne) { 943 | break; 944 | } 945 | 946 | LZ4_putPosition(ip - 2, cctx->hashTable, tableType, base); 947 | 948 | if(tableType == LZ4_byPtr) { 949 | match = LZ4_getPosition(ip, cctx->hashTable, tableType, base); 950 | LZ4_putPosition(ip, cctx->hashTable, tableType, base); 951 | if((match + LZ4_DISTANCE_MAX >= ip) && (LZ4_read32(match) == LZ4_read32(ip))) { 952 | token = op++; 953 | *token = 0; 954 | goto _next_match; 955 | } 956 | 957 | } else { 958 | LZ4_u32 const h = LZ4_hashPosition(ip, tableType); 959 | LZ4_u32 const current = (LZ4_u32) (ip-base); 960 | LZ4_u32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType); 961 | assert(matchIndex < current); 962 | if(dictDirective == LZ4_usingDictCtx) { 963 | if(matchIndex < startIndex) { 964 | matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, LZ4_byU32); 965 | match = dictBase + matchIndex; 966 | lowLimit = dictionary; 967 | matchIndex += dictDelta; 968 | } else { 969 | match = base + matchIndex; 970 | lowLimit = (LZ4_byte const *) source; 971 | } 972 | } else if(dictDirective == LZ4_usingExtDict) { 973 | if(matchIndex < startIndex) { 974 | assert(dictBase); 975 | match = dictBase + matchIndex; 976 | lowLimit = dictionary; 977 | } else { 978 | match = base + matchIndex; 979 | lowLimit = (LZ4_byte const *) source; 980 | } 981 | } else { 982 | match = base + matchIndex; 983 | } 984 | 985 | LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType); 986 | assert(matchIndex < current); 987 | if(((dictIssue == LZ4_dictSmall) ? (matchIndex >= prefixIdxLimit) : 1) && (((tableType == LZ4_byU16) && (LZ4_DISTANCE_MAX == LZ4_DISTANCE_ABSOLUTE_MAX)) ? 1 : (matchIndex + LZ4_DISTANCE_MAX >= current)) && (LZ4_read32(match) == LZ4_read32(ip))) { 988 | token = op++; 989 | *token = 0; 990 | if(maybe_extMem) offset = current - matchIndex; 991 | goto _next_match; 992 | } 993 | } 994 | 995 | forwardH = LZ4_hashPosition(++ip, tableType); 996 | } 997 | 998 | _last_literals: 999 | { 1000 | size_t lastRun = (size_t) (iend - anchor); 1001 | if((outputDirective) && (op + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > olimit)) { 1002 | if(outputDirective == LZ4_fillOutput) { 1003 | assert(olimit >= op); 1004 | lastRun = (size_t) (olimit-op) - 1; 1005 | lastRun -= (lastRun + 256 - RUN_MASK) / 256; 1006 | } else { 1007 | assert(outputDirective == LZ4_limitedOutput); 1008 | return 0; 1009 | } 1010 | } 1011 | 1012 | if(lastRun >= RUN_MASK) { 1013 | size_t accumulator = lastRun - RUN_MASK; 1014 | *op++ = RUN_MASK << ML_BITS; 1015 | for(; accumulator >= 255; accumulator-=255) *op++ = 255; 1016 | *op++ = (LZ4_byte) accumulator; 1017 | } else { 1018 | *op++ = (LZ4_byte) (lastRun << ML_BITS); 1019 | } 1020 | (void) UTRACY_MEMCPY(op, anchor, lastRun); 1021 | ip = anchor + lastRun; 1022 | op += lastRun; 1023 | } 1024 | 1025 | if(outputDirective == LZ4_fillOutput) { 1026 | *inputConsumed = (int) (((char const *) ip) - source); 1027 | } 1028 | result = (int) (((char *) op) - dest); 1029 | assert(result > 0); 1030 | return result; 1031 | } 1032 | 1033 | UTRACY_INTERNAL UTRACY_INLINE 1034 | int LZ4_compress_generic(LZ4_stream_t_internal *const cctx, char const *const src, char *const dst, int const srcSize, int *inputConsumed, int const dstCapacity, LZ4_limitedOutput_directive const outputDirective, LZ4_tableType_t const tableType, LZ4_dict_directive const dictDirective, LZ4_dictIssue_directive const dictIssue, int const acceleration) { 1035 | if((LZ4_u32) srcSize > (LZ4_u32) LZ4_MAX_INPUT_SIZE) { 1036 | return 0; 1037 | } 1038 | 1039 | if(srcSize == 0) { 1040 | if(outputDirective != LZ4_notLimited && dstCapacity <= 0) return 0; 1041 | assert(outputDirective == LZ4_notLimited || dstCapacity >= 1); 1042 | assert(dst != NULL); 1043 | dst[0] = 0; 1044 | if(outputDirective == LZ4_fillOutput) { 1045 | assert(inputConsumed != NULL); 1046 | *inputConsumed = 0; 1047 | } 1048 | return 1; 1049 | } 1050 | 1051 | assert(src != NULL); 1052 | 1053 | return LZ4_compress_generic_validated( 1054 | cctx, 1055 | src, 1056 | dst, 1057 | srcSize, 1058 | inputConsumed, 1059 | dstCapacity, 1060 | outputDirective, 1061 | tableType, 1062 | dictDirective, 1063 | dictIssue, 1064 | acceleration 1065 | ); 1066 | } 1067 | 1068 | 1069 | UTRACY_INTERNAL UTRACY_INLINE 1070 | int LZ4_compress_fast_continue(LZ4_stream_t *LZ4_stream, char const *source, char *dest, int inputSize, int maxOutputSize, int acceleration) { 1071 | LZ4_tableType_t const tableType = LZ4_byU32; 1072 | LZ4_stream_t_internal *const streamPtr = &LZ4_stream->internal_donotuse; 1073 | char const *dictEnd = streamPtr->dictSize ? (char const *) streamPtr->dictionary + streamPtr->dictSize : NULL; 1074 | 1075 | LZ4_renormDictT(streamPtr, inputSize); 1076 | if(acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT; 1077 | if(acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX; 1078 | 1079 | if((streamPtr->dictSize < 4) && (dictEnd != source) && (inputSize > 0) && (streamPtr->dictCtx == NULL)) { 1080 | streamPtr->dictSize = 0; 1081 | streamPtr->dictionary = (LZ4_byte const *) source; 1082 | dictEnd = source; 1083 | } 1084 | 1085 | { 1086 | char const *const sourceEnd = source + inputSize; 1087 | if((sourceEnd > (char const *) streamPtr->dictionary) && (sourceEnd < dictEnd)) { 1088 | streamPtr->dictSize = (LZ4_u32) (dictEnd - sourceEnd); 1089 | if(streamPtr->dictSize > 65536u) streamPtr->dictSize = 65536u; 1090 | if(streamPtr->dictSize < 4u) streamPtr->dictSize = 0; 1091 | streamPtr->dictionary = (LZ4_byte const *) dictEnd - streamPtr->dictSize; 1092 | } 1093 | } 1094 | 1095 | if(dictEnd == source) { 1096 | if((streamPtr->dictSize < 65536u) && (streamPtr->dictSize < streamPtr->currentOffset)) { 1097 | return LZ4_compress_generic( 1098 | streamPtr, 1099 | source, 1100 | dest, 1101 | inputSize, 1102 | NULL, 1103 | maxOutputSize, 1104 | LZ4_limitedOutput, 1105 | tableType, 1106 | LZ4_withPrefix64k, 1107 | LZ4_dictSmall, 1108 | acceleration 1109 | ); 1110 | } else { 1111 | return LZ4_compress_generic( 1112 | streamPtr, 1113 | source, 1114 | dest, 1115 | inputSize, 1116 | NULL, 1117 | maxOutputSize, 1118 | LZ4_limitedOutput, 1119 | tableType, 1120 | LZ4_withPrefix64k, 1121 | LZ4_noDictIssue, 1122 | acceleration 1123 | ); 1124 | } 1125 | } 1126 | 1127 | { 1128 | int result; 1129 | if(streamPtr->dictCtx) { 1130 | if(inputSize > 4096) { 1131 | (void) UTRACY_MEMCPY(streamPtr, streamPtr->dictCtx, sizeof(*streamPtr)); 1132 | result = LZ4_compress_generic( 1133 | streamPtr, 1134 | source, 1135 | dest, 1136 | inputSize, 1137 | NULL, 1138 | maxOutputSize, 1139 | LZ4_limitedOutput, 1140 | tableType, 1141 | LZ4_usingExtDict, 1142 | LZ4_noDictIssue, 1143 | acceleration 1144 | ); 1145 | } else { 1146 | result = LZ4_compress_generic( 1147 | streamPtr, 1148 | source, 1149 | dest, 1150 | inputSize, 1151 | NULL, 1152 | maxOutputSize, 1153 | LZ4_limitedOutput, 1154 | tableType, 1155 | LZ4_usingDictCtx, 1156 | LZ4_noDictIssue, 1157 | acceleration 1158 | ); 1159 | } 1160 | } else { 1161 | if ((streamPtr->dictSize < 65536u) && (streamPtr->dictSize < streamPtr->currentOffset)) { 1162 | result = LZ4_compress_generic( 1163 | streamPtr, 1164 | source, 1165 | dest, 1166 | inputSize, 1167 | NULL, 1168 | maxOutputSize, 1169 | LZ4_limitedOutput, 1170 | tableType, 1171 | LZ4_usingExtDict, 1172 | LZ4_dictSmall, 1173 | acceleration 1174 | ); 1175 | } else { 1176 | result = LZ4_compress_generic( 1177 | streamPtr, 1178 | source, 1179 | dest, 1180 | inputSize, 1181 | NULL, 1182 | maxOutputSize, 1183 | LZ4_limitedOutput, 1184 | tableType, 1185 | LZ4_usingExtDict, 1186 | LZ4_noDictIssue, 1187 | acceleration 1188 | ); 1189 | } 1190 | } 1191 | 1192 | streamPtr->dictionary = (LZ4_byte const *) source; 1193 | streamPtr->dictSize = (LZ4_u32) inputSize; 1194 | return result; 1195 | } 1196 | } 1197 | 1198 | UTRACY_INTERNAL UTRACY_INLINE 1199 | int LZ4_isAligned(void const *ptr, size_t alignment) { 1200 | return ((size_t) ptr & (alignment - 1)) == 0; 1201 | } 1202 | 1203 | UTRACY_INTERNAL UTRACY_INLINE 1204 | size_t LZ4_stream_t_alignment(void) { 1205 | typedef struct {char c; LZ4_stream_t t;} t_a; 1206 | return sizeof(t_a) - sizeof(LZ4_stream_t); 1207 | } 1208 | 1209 | UTRACY_INTERNAL UTRACY_INLINE 1210 | LZ4_stream_t *LZ4_initStream(void *buffer, size_t size) { 1211 | if(buffer == NULL) {return NULL;} 1212 | if(size < sizeof(LZ4_stream_t)) {return NULL;} 1213 | if(!LZ4_isAligned(buffer, LZ4_stream_t_alignment())) return NULL; 1214 | (void) UTRACY_MEMSET(buffer, 0, sizeof(LZ4_stream_t_internal)); 1215 | return (LZ4_stream_t *) buffer; 1216 | } 1217 | 1218 | UTRACY_INTERNAL UTRACY_INLINE 1219 | void LZ4_resetStream_fast(LZ4_stream_t *ctx) { 1220 | LZ4_prepareTable(&(ctx->internal_donotuse), 0, LZ4_byU32); 1221 | } 1222 | 1223 | /* queue */ 1224 | #if defined(__STDC_NO_ATOMICS__) 1225 | # define atomic_load_relaxed(a) *(a) 1226 | # define atomic_load_acquire(a) *(a) 1227 | # define atomic_store_seqcst(a, b) *(a) = (b) 1228 | # define atomic_store_release(a, b) *(a) = (b) 1229 | #else 1230 | # define atomic_load_relaxed(a) atomic_load_explicit((a), memory_order_relaxed) 1231 | # define atomic_load_acquire(a) atomic_load_explicit((a), memory_order_acquire) 1232 | # define atomic_store_seqcst(a, b) atomic_store_explicit((a), (b), memory_order_seq_cst) 1233 | # define atomic_store_release(a, b) atomic_store_explicit((a), (b), memory_order_release) 1234 | #endif 1235 | 1236 | struct event_zone_begin { 1237 | int unsigned tid; 1238 | void *srcloc; 1239 | long long timestamp; 1240 | }; 1241 | 1242 | struct event_zone_end { 1243 | int unsigned tid; 1244 | long long timestamp; 1245 | }; 1246 | 1247 | struct event_zone_color { 1248 | int unsigned tid; 1249 | int unsigned color; 1250 | }; 1251 | 1252 | struct event_frame_mark { 1253 | void *name; 1254 | long long timestamp; 1255 | }; 1256 | 1257 | struct event { 1258 | char unsigned type; 1259 | union { 1260 | struct event_zone_begin zone_begin; 1261 | struct event_zone_end zone_end; 1262 | struct event_zone_color zone_color; 1263 | struct event_frame_mark frame_mark; 1264 | }; 1265 | }; 1266 | 1267 | /* data */ 1268 | static struct { 1269 | struct string ***strings; 1270 | int unsigned *strings_len; 1271 | struct misc ***miscs; 1272 | int unsigned *miscs_len; 1273 | /* procdef array address */ 1274 | char **procdefs; 1275 | /* procdef array length */ 1276 | int unsigned *procdefs_len; 1277 | /* procdef descriptor */ 1278 | struct { 1279 | /* total size */ 1280 | int unsigned size; 1281 | /* offsets */ 1282 | int unsigned path; 1283 | int unsigned bytecode; 1284 | } procdef_desc; 1285 | void *exec_proc; 1286 | struct object (UTRACY_WINDOWS_CDECL UTRACY_LINUX_REGPARM(3) *orig_exec_proc)(struct proc *); 1287 | void *server_tick; 1288 | int (UTRACY_WINDOWS_STDCALL UTRACY_LINUX_CDECL *orig_server_tick)(void); 1289 | void *send_maps; 1290 | void (UTRACY_WINDOWS_CDECL UTRACY_LINUX_CDECL *orig_send_maps)(void); 1291 | _Alignas(UTRACY_PAGE_SIZE) struct { 1292 | char exec_proc[32]; 1293 | char server_tick[32]; 1294 | char send_maps[32]; 1295 | } trampoline; 1296 | } byond; 1297 | 1298 | static struct { 1299 | struct { 1300 | long long init_begin; 1301 | long long init_end; 1302 | double multiplier; 1303 | long long resolution; 1304 | long long delay; 1305 | long long epoch; 1306 | long long exec_time; 1307 | } info; 1308 | 1309 | struct { 1310 | int unsigned version; 1311 | 1312 | char unsigned zone_begin; 1313 | char unsigned zone_end; 1314 | char unsigned zone_color; 1315 | char unsigned thread_context; 1316 | char unsigned framemark; 1317 | 1318 | char unsigned response_source_location; 1319 | char unsigned response_server_query_noop; 1320 | char unsigned response_source_code_unavail; 1321 | char unsigned response_symbol_code_unavail; 1322 | char unsigned response_string_data; 1323 | char unsigned response_thread_name; 1324 | 1325 | char unsigned query_terminate; 1326 | char unsigned query_string; 1327 | char unsigned query_thread_string; 1328 | char unsigned query_source_location; 1329 | char unsigned query_disconnect; 1330 | char unsigned query_symbol_code; 1331 | char unsigned query_source_code; 1332 | char unsigned query_data_transfer; 1333 | char unsigned query_data_transfer_part; 1334 | } protocol; 1335 | 1336 | struct { 1337 | int connected; 1338 | #if defined(UTRACY_WINDOWS) 1339 | WSADATA wsa; 1340 | SOCKET server; 1341 | SOCKET client; 1342 | #elif defined(UTRACY_LINUX) 1343 | int server; 1344 | int client; 1345 | #endif 1346 | } sock; 1347 | 1348 | struct { 1349 | struct { 1350 | int unsigned tid; 1351 | long long timestamp; 1352 | } cur_thread; 1353 | 1354 | long long prev_commit; 1355 | LZ4_stream_t stream; 1356 | 1357 | int unsigned raw_buf_head; 1358 | int unsigned raw_buf_tail; 1359 | char raw_buf[UTRACY_MAX_FRAME_SIZE * 3]; 1360 | 1361 | int unsigned frame_buf_len; 1362 | char frame_buf[sizeof(int) + LZ4_COMPRESSBOUND(UTRACY_MAX_FRAME_SIZE)]; 1363 | } data; 1364 | 1365 | struct { 1366 | int unsigned producer_tail_cache; 1367 | int unsigned consumer_head_cache; 1368 | struct event events[EVENT_QUEUE_CAPACITY]; 1369 | 1370 | #if defined(__STDC_NO_ATOMICS__) 1371 | long volatile head; 1372 | long volatile tail; 1373 | #else 1374 | _Alignas(UTRACY_L1_LINE_SIZE) atomic_uint head; 1375 | _Alignas(UTRACY_L1_LINE_SIZE) atomic_uint tail; 1376 | _Alignas(UTRACY_L1_LINE_SIZE) int padding; 1377 | #endif 1378 | } queue; 1379 | } utracy; 1380 | 1381 | /* queue api */ 1382 | UTRACY_INTERNAL UTRACY_INLINE 1383 | int event_queue_init(void) { 1384 | utracy.queue.producer_tail_cache = 0; 1385 | utracy.queue.consumer_head_cache = 0; 1386 | atomic_store_seqcst(&utracy.queue.head, 1); 1387 | atomic_store_seqcst(&utracy.queue.tail, 0); 1388 | return 0; 1389 | } 1390 | 1391 | UTRACY_INTERNAL UTRACY_INLINE 1392 | void event_queue_push(struct event const *const event) { 1393 | int unsigned store = atomic_load_relaxed(&utracy.queue.head); 1394 | int unsigned next_store = store + 1; 1395 | 1396 | if(next_store == EVENT_QUEUE_CAPACITY) { 1397 | next_store = 0; 1398 | } 1399 | 1400 | while(unlikely(next_store == utracy.queue.producer_tail_cache)) { 1401 | utracy.queue.producer_tail_cache = atomic_load_acquire(&utracy.queue.tail); 1402 | } 1403 | 1404 | utracy.queue.events[store] = *event; 1405 | 1406 | atomic_store_release(&utracy.queue.head, next_store); 1407 | } 1408 | 1409 | UTRACY_INTERNAL UTRACY_INLINE 1410 | int event_queue_pop(struct event *const event) { 1411 | int unsigned load = atomic_load_relaxed(&utracy.queue.tail); 1412 | int unsigned next_load = load + 1; 1413 | 1414 | if(load == utracy.queue.consumer_head_cache) { 1415 | utracy.queue.consumer_head_cache = atomic_load_acquire(&utracy.queue.head); 1416 | if(load == utracy.queue.consumer_head_cache) { 1417 | return -1; 1418 | } 1419 | } 1420 | 1421 | *event = utracy.queue.events[load]; 1422 | 1423 | if(next_load == EVENT_QUEUE_CAPACITY) { 1424 | next_load = 0; 1425 | } 1426 | 1427 | atomic_store_release(&utracy.queue.tail, next_load); 1428 | return 0; 1429 | } 1430 | 1431 | /* profiler */ 1432 | UTRACY_INTERNAL UTRACY_INLINE 1433 | long long utracy_tsc(void) { 1434 | #if defined(UTRACY_CLANG) || defined(UTRACY_GCC) 1435 | return (long long) __builtin_ia32_rdtsc(); 1436 | #elif defined(UTRACY_MSVC) 1437 | return (long long) __rdtsc(); 1438 | #else 1439 | int unsigned eax, edx; 1440 | __asm__ __volatile__("rdtsc;" :"=a"(eax), "=d"(edx)); 1441 | return ((long long) edx << 32) + eax; 1442 | #endif 1443 | } 1444 | 1445 | #if defined(UTRACY_LINUX) 1446 | static int unsigned linux_main_tid; 1447 | #endif 1448 | 1449 | UTRACY_INTERNAL UTRACY_INLINE 1450 | int unsigned utracy_tid(void) { 1451 | #if defined(UTRACY_WINDOWS) 1452 | # if defined(UTRACY_CLANG) || defined(UTRACY_GCC) 1453 | 1454 | int unsigned tid; 1455 | __asm__("mov %%fs:0x24, %0;" :"=r"(tid)); 1456 | return tid; 1457 | 1458 | # elif defined(UTRACY_MSVC) 1459 | 1460 | __asm { 1461 | mov eax, fs:[0x24]; 1462 | } 1463 | 1464 | # else 1465 | 1466 | return GetCurrentThreadId(); 1467 | 1468 | # endif 1469 | #elif defined(UTRACY_LINUX) 1470 | /* too damn slow 1471 | return syscall(__NR_gettid); */ 1472 | return linux_main_tid; 1473 | #endif 1474 | } 1475 | 1476 | UTRACY_INTERNAL 1477 | double calibrate_multiplier(void) { 1478 | #if defined(UTRACY_WINDOWS) 1479 | LARGE_INTEGER li_freq, li_t0, li_t1; 1480 | if(0 == QueryPerformanceFrequency(&li_freq)) { 1481 | LOG_DEBUG_ERROR; 1482 | return 1.0; 1483 | } 1484 | 1485 | if(0 == QueryPerformanceCounter(&li_t0)) { 1486 | LOG_DEBUG_ERROR; 1487 | return 1.0; 1488 | } 1489 | 1490 | long long clk0 = utracy_tsc(); 1491 | 1492 | Sleep(100); 1493 | 1494 | if(0 == QueryPerformanceCounter(&li_t1)) { 1495 | LOG_DEBUG_ERROR; 1496 | return 1.0; 1497 | } 1498 | 1499 | long long clk1 = utracy_tsc(); 1500 | 1501 | double const freq = li_freq.QuadPart; 1502 | double const t0 = li_t0.QuadPart; 1503 | double const t1 = li_t1.QuadPart; 1504 | double const dt = ((t1 - t0) * 1000000000.0) / freq; 1505 | double const dclk = clk1 - clk0; 1506 | 1507 | if(clk0 >= clk1) { 1508 | LOG_DEBUG_ERROR; 1509 | return 1.0; 1510 | } 1511 | 1512 | if(t0 >= t1) { 1513 | LOG_DEBUG_ERROR; 1514 | return 1.0; 1515 | } 1516 | 1517 | if(0.0 >= dclk) { 1518 | LOG_DEBUG_ERROR; 1519 | return 1.0; 1520 | } 1521 | 1522 | return dt / dclk; 1523 | 1524 | #elif defined(UTRACY_LINUX) 1525 | struct timespec ts_t0, ts_t1; 1526 | 1527 | interrupted: 1528 | if(-1 == clock_gettime(CLOCK_MONOTONIC_RAW, &ts_t0)) { 1529 | LOG_DEBUG_ERROR; 1530 | return 1.0; 1531 | } 1532 | 1533 | long long clk0 = utracy_tsc(); 1534 | 1535 | if(-1 == usleep(100000)) { 1536 | LOG_DEBUG_ERROR; 1537 | 1538 | if(EINTR == errno) { 1539 | goto interrupted; 1540 | } 1541 | 1542 | return 1.0; 1543 | } 1544 | 1545 | if(-1 == clock_gettime(CLOCK_MONOTONIC_RAW, &ts_t1)) { 1546 | LOG_DEBUG_ERROR; 1547 | return 1.0; 1548 | } 1549 | 1550 | long long clk1 = utracy_tsc(); 1551 | 1552 | double const t0 = ts_t0.tv_sec * 1000000000.0 + ts_t0.tv_nsec; 1553 | double const t1 = ts_t1.tv_sec * 1000000000.0 + ts_t1.tv_nsec; 1554 | double const dt = t1 - t0; 1555 | double const dclk = clk1 - clk0; 1556 | 1557 | if(clk0 >= clk1) { 1558 | LOG_DEBUG_ERROR; 1559 | return 1.0; 1560 | } 1561 | 1562 | if(t0 >= t1) { 1563 | LOG_DEBUG_ERROR; 1564 | return 1.0; 1565 | } 1566 | 1567 | if(0.0 >= dclk) { 1568 | LOG_DEBUG_ERROR; 1569 | return 1.0; 1570 | } 1571 | 1572 | return dt / dclk; 1573 | 1574 | #endif 1575 | } 1576 | 1577 | UTRACY_INTERNAL 1578 | long long calibrate_resolution(void) { 1579 | /* many iterations may be required to allow the thread time to migrate 1580 | to a suitable cpu / C-state / P-state */ 1581 | int const iterations = 1000000; 1582 | long long resolution = 0x7FFFFFFFFFFFFFFFll; 1583 | 1584 | for(int i=0; iai_addrlen; 1796 | struct sockaddr_in *addr = (struct sockaddr_in *) result->ai_addr; 1797 | 1798 | if(0 > bind(utracy.sock.server, (struct sockaddr *) addr, addrlen)) { 1799 | LOG_DEBUG_ERROR; 1800 | freeaddrinfo(result); 1801 | return -1; 1802 | } 1803 | 1804 | if(0 > listen(utracy.sock.server, 2)) { 1805 | LOG_DEBUG_ERROR; 1806 | freeaddrinfo(result); 1807 | return -1; 1808 | } 1809 | 1810 | #if defined(UTRACY_DEBUG) 1811 | char ip[INET_ADDRSTRLEN]; 1812 | if(NULL == inet_ntop(AF_INET, &addr->sin_addr, ip, sizeof(ip))) { 1813 | LOG_DEBUG_ERROR; 1814 | freeaddrinfo(result); 1815 | return -1; 1816 | } 1817 | 1818 | LOG_INFO("listening on %s:%hu\n", ip, ntohs(addr->sin_port)); 1819 | #endif 1820 | 1821 | freeaddrinfo(result); 1822 | 1823 | return 0; 1824 | } 1825 | 1826 | UTRACY_INTERNAL 1827 | int utracy_protocol_init(int unsigned version) { 1828 | utracy.protocol.version = version; 1829 | 1830 | switch(version) { 1831 | case UTRACY_PROTOCOL_0_8_1: 1832 | case UTRACY_PROTOCOL_0_8_2: 1833 | utracy.protocol.zone_begin = 15; 1834 | utracy.protocol.zone_end = 17; 1835 | utracy.protocol.zone_color = 62; 1836 | utracy.protocol.thread_context = 57; 1837 | utracy.protocol.framemark = 64; 1838 | 1839 | utracy.protocol.response_source_location = 67; 1840 | utracy.protocol.response_server_query_noop = 87; 1841 | utracy.protocol.response_source_code_unavail = 88; 1842 | utracy.protocol.response_symbol_code_unavail = 89; 1843 | utracy.protocol.response_string_data = 94; 1844 | utracy.protocol.response_thread_name = 95; 1845 | 1846 | utracy.protocol.query_terminate = 0; 1847 | utracy.protocol.query_string = 1; 1848 | utracy.protocol.query_thread_string = 2; 1849 | utracy.protocol.query_source_location = 3; 1850 | utracy.protocol.query_disconnect = 8; 1851 | utracy.protocol.query_symbol_code = 12; 1852 | utracy.protocol.query_source_code = 14; 1853 | utracy.protocol.query_data_transfer = 15; 1854 | utracy.protocol.query_data_transfer_part = 16; 1855 | break; 1856 | 1857 | /* also covers 0.9.1 */ 1858 | case UTRACY_PROTOCOL_0_9_0: 1859 | utracy.protocol.zone_begin = 15; 1860 | utracy.protocol.zone_end = 17; 1861 | utracy.protocol.zone_color = 64; 1862 | utracy.protocol.thread_context = 59; 1863 | utracy.protocol.framemark = 66; 1864 | 1865 | utracy.protocol.response_source_location = 70; 1866 | utracy.protocol.response_server_query_noop = 90; 1867 | utracy.protocol.response_source_code_unavail = 91; 1868 | utracy.protocol.response_symbol_code_unavail = 92; 1869 | utracy.protocol.response_string_data = 97; 1870 | utracy.protocol.response_thread_name = 98; 1871 | 1872 | utracy.protocol.query_terminate = 0; 1873 | utracy.protocol.query_string = 1; 1874 | utracy.protocol.query_thread_string = 2; 1875 | utracy.protocol.query_source_location = 3; 1876 | utracy.protocol.query_disconnect = 8; 1877 | utracy.protocol.query_symbol_code = 12; 1878 | utracy.protocol.query_source_code = 13; 1879 | utracy.protocol.query_data_transfer = 14; 1880 | utracy.protocol.query_data_transfer_part = 15; 1881 | break; 1882 | 1883 | case UTRACY_PROTOCOL_0_10_0: 1884 | utracy.protocol.zone_begin = 15; 1885 | utracy.protocol.zone_end = 17; 1886 | utracy.protocol.zone_color = 64; 1887 | utracy.protocol.thread_context = 59; 1888 | utracy.protocol.framemark = 66; 1889 | 1890 | utracy.protocol.response_source_location = 70; 1891 | utracy.protocol.response_server_query_noop = 91; 1892 | utracy.protocol.response_source_code_unavail = 92; 1893 | utracy.protocol.response_symbol_code_unavail = 93; 1894 | utracy.protocol.response_string_data = 98; 1895 | utracy.protocol.response_thread_name = 99; 1896 | 1897 | utracy.protocol.query_terminate = 0; 1898 | utracy.protocol.query_string = 1; 1899 | utracy.protocol.query_thread_string = 2; 1900 | utracy.protocol.query_source_location = 3; 1901 | utracy.protocol.query_disconnect = 8; 1902 | utracy.protocol.query_symbol_code = 12; 1903 | utracy.protocol.query_source_code = 13; 1904 | utracy.protocol.query_data_transfer = 14; 1905 | utracy.protocol.query_data_transfer_part = 15; 1906 | break; 1907 | 1908 | case UTRACY_PROTOCOL_0_11_0: 1909 | utracy.protocol.zone_begin = 15; 1910 | utracy.protocol.zone_end = 17; 1911 | utracy.protocol.zone_color = 65; 1912 | utracy.protocol.thread_context = 59; 1913 | utracy.protocol.framemark = 67; 1914 | 1915 | utracy.protocol.response_source_location = 71; 1916 | utracy.protocol.response_server_query_noop = 92; 1917 | utracy.protocol.response_source_code_unavail = 93; 1918 | utracy.protocol.response_symbol_code_unavail = 94; 1919 | utracy.protocol.response_string_data = 99; 1920 | utracy.protocol.response_thread_name = 100; 1921 | 1922 | utracy.protocol.query_terminate = 0; 1923 | utracy.protocol.query_string = 1; 1924 | utracy.protocol.query_thread_string = 2; 1925 | utracy.protocol.query_source_location = 3; 1926 | utracy.protocol.query_disconnect = 9; 1927 | utracy.protocol.query_symbol_code = 12; 1928 | utracy.protocol.query_source_code = 13; 1929 | utracy.protocol.query_data_transfer = 14; 1930 | utracy.protocol.query_data_transfer_part = 15; 1931 | break; 1932 | 1933 | case UTRACY_PROTOCOL_0_11_1: 1934 | utracy.protocol.zone_begin = 15; 1935 | utracy.protocol.zone_end = 17; 1936 | utracy.protocol.zone_color = 65; 1937 | utracy.protocol.thread_context = 59; 1938 | utracy.protocol.framemark = 67; 1939 | 1940 | utracy.protocol.response_source_location = 71; 1941 | utracy.protocol.response_server_query_noop = 92; 1942 | utracy.protocol.response_source_code_unavail = 93; 1943 | utracy.protocol.response_symbol_code_unavail = 94; 1944 | utracy.protocol.response_string_data = 100; 1945 | utracy.protocol.response_thread_name = 101; 1946 | 1947 | utracy.protocol.query_terminate = 0; 1948 | utracy.protocol.query_string = 1; 1949 | utracy.protocol.query_thread_string = 2; 1950 | utracy.protocol.query_source_location = 3; 1951 | utracy.protocol.query_disconnect = 9; 1952 | utracy.protocol.query_symbol_code = 12; 1953 | utracy.protocol.query_source_code = 13; 1954 | utracy.protocol.query_data_transfer = 14; 1955 | utracy.protocol.query_data_transfer_part = 15; 1956 | break; 1957 | 1958 | default: 1959 | return -1; 1960 | } 1961 | 1962 | return 0; 1963 | } 1964 | 1965 | UTRACY_INTERNAL 1966 | int utracy_client_accept(void) { 1967 | struct sockaddr_in client; 1968 | 1969 | socklen_t len = sizeof(client); 1970 | if(0 > (utracy.sock.client = accept(utracy.sock.server, (struct sockaddr *) &client, &len))) { 1971 | LOG_DEBUG_ERROR; 1972 | return -1; 1973 | } 1974 | 1975 | char ip[INET_ADDRSTRLEN]; 1976 | if(NULL == inet_ntop(AF_INET, &client.sin_addr, ip, sizeof(ip))) { 1977 | LOG_DEBUG_ERROR; 1978 | return -1; 1979 | } 1980 | 1981 | LOG_INFO("received connection: %s\n", ip); 1982 | utracy.sock.connected = 1; 1983 | 1984 | return 0; 1985 | } 1986 | 1987 | UTRACY_INTERNAL 1988 | int utracy_client_recv(void *const buf, int unsigned len) { 1989 | size_t offset = 0; 1990 | 1991 | while(offset < len) { 1992 | int received = recv(utracy.sock.client, (char *) buf + offset, len - offset, 0); 1993 | 1994 | if(0 >= received) { 1995 | LOG_DEBUG_ERROR; 1996 | 1997 | #if defined(UTRACY_LINUX) 1998 | if(EINTR == errno) { 1999 | continue; 2000 | } 2001 | #endif 2002 | 2003 | return -1; 2004 | } 2005 | 2006 | offset += received; 2007 | } 2008 | 2009 | return 0; 2010 | } 2011 | 2012 | UTRACY_INTERNAL 2013 | int utracy_client_send(void *const buf, int unsigned len) { 2014 | size_t offset = 0; 2015 | 2016 | while(offset < len) { 2017 | int sent = send(utracy.sock.client, (char *) buf + offset, len - offset, 0); 2018 | 2019 | if(0 >= sent) { 2020 | LOG_DEBUG_ERROR; 2021 | 2022 | #if defined(UTRACY_LINUX) 2023 | if(EINTR == errno) { 2024 | continue; 2025 | } 2026 | #endif 2027 | 2028 | return -1; 2029 | } 2030 | 2031 | offset += sent; 2032 | } 2033 | 2034 | return 0; 2035 | } 2036 | 2037 | UTRACY_INTERNAL 2038 | int utracy_commit(void) { 2039 | if(0 < utracy.data.raw_buf_head - utracy.data.raw_buf_tail) { 2040 | int unsigned pending_len; 2041 | pending_len = utracy.data.raw_buf_head - utracy.data.raw_buf_tail; 2042 | 2043 | do { 2044 | int unsigned raw_frame_len = min(pending_len, UTRACY_MAX_FRAME_SIZE); 2045 | 2046 | /* write compressed buf */ 2047 | int unsigned compressed_len = LZ4_compress_fast_continue( 2048 | &utracy.data.stream, 2049 | /* src */ 2050 | utracy.data.raw_buf + utracy.data.raw_buf_tail, 2051 | /* dst */ 2052 | utracy.data.frame_buf + sizeof(int), 2053 | /* src len */ 2054 | raw_frame_len, 2055 | /* dst max len */ 2056 | LZ4_COMPRESSBOUND(UTRACY_MAX_FRAME_SIZE), 2057 | 1 2058 | ); 2059 | 2060 | /* write compressed buf len */ 2061 | (void) UTRACY_MEMCPY(utracy.data.frame_buf + 0, &compressed_len, sizeof(compressed_len)); 2062 | 2063 | /* transmit frame */ 2064 | if(0 != utracy_client_send(utracy.data.frame_buf, compressed_len + sizeof(compressed_len))) { 2065 | LOG_DEBUG_ERROR; 2066 | return -1; 2067 | } 2068 | 2069 | /* advance tail */ 2070 | utracy.data.raw_buf_tail += raw_frame_len; 2071 | pending_len = utracy.data.raw_buf_head - utracy.data.raw_buf_tail; 2072 | } while(0 < pending_len); 2073 | 2074 | /* previous 64kb of uncompressed data must remain unclobbered at the 2075 | same memory address! */ 2076 | if(utracy.data.raw_buf_head >= UTRACY_MAX_FRAME_SIZE * 2) { 2077 | utracy.data.raw_buf_head = 0; 2078 | utracy.data.raw_buf_tail = 0; 2079 | } 2080 | 2081 | utracy.data.prev_commit = utracy_tsc(); 2082 | } 2083 | 2084 | return 0; 2085 | } 2086 | 2087 | UTRACY_INTERNAL UTRACY_INLINE 2088 | int utracy_write_packet(void const *const buf, int unsigned len) { 2089 | int unsigned current_frame_size = utracy.data.raw_buf_head - utracy.data.raw_buf_tail; 2090 | 2091 | if(current_frame_size + len > UTRACY_MAX_FRAME_SIZE) { 2092 | if(0 != utracy_commit()) { 2093 | LOG_DEBUG_ERROR; 2094 | return -1; 2095 | } 2096 | } 2097 | 2098 | if(len > sizeof(utracy.data.raw_buf) - utracy.data.raw_buf_head) { 2099 | LOG_DEBUG_ERROR; 2100 | return -1; 2101 | } 2102 | 2103 | (void) UTRACY_MEMCPY(utracy.data.raw_buf + utracy.data.raw_buf_head, buf, len); 2104 | utracy.data.raw_buf_head += len; 2105 | 2106 | return 0; 2107 | } 2108 | 2109 | UTRACY_INTERNAL UTRACY_INLINE 2110 | int utracy_write_server_context(int unsigned tid) { 2111 | #pragma pack(push, 1) 2112 | struct network_thread_context { 2113 | char unsigned type; 2114 | int unsigned tid; 2115 | }; 2116 | 2117 | _Static_assert(5 == sizeof(struct network_thread_context), "incorrect size"); 2118 | #pragma pack(pop) 2119 | 2120 | struct network_thread_context msg = { 2121 | .type = utracy.protocol.thread_context, 2122 | .tid = tid 2123 | }; 2124 | 2125 | if(0 != utracy_write_packet(&msg, sizeof(msg))) { 2126 | LOG_DEBUG_ERROR; 2127 | return -1; 2128 | } 2129 | 2130 | return 0; 2131 | } 2132 | 2133 | UTRACY_INTERNAL UTRACY_INLINE 2134 | int utracy_write_zone_begin(struct event evt) { 2135 | #pragma pack(push, 1) 2136 | struct network_zone_begin { 2137 | char unsigned type; 2138 | long long timestamp; 2139 | long long unsigned srcloc; 2140 | }; 2141 | _Static_assert(17 == sizeof(struct network_zone_begin), "incorrect size"); 2142 | #pragma pack(pop) 2143 | 2144 | long long timestamp = evt.zone_begin.timestamp - utracy.data.cur_thread.timestamp; 2145 | utracy.data.cur_thread.timestamp = evt.zone_begin.timestamp; 2146 | 2147 | struct network_zone_begin msg = { 2148 | .type = utracy.protocol.zone_begin, 2149 | .timestamp = timestamp, 2150 | .srcloc = (uintptr_t) evt.zone_begin.srcloc 2151 | }; 2152 | 2153 | if(0 != utracy_write_packet(&msg, sizeof(msg))) { 2154 | LOG_DEBUG_ERROR; 2155 | return -1; 2156 | } 2157 | 2158 | return 0; 2159 | } 2160 | 2161 | UTRACY_INTERNAL UTRACY_INLINE 2162 | int utracy_write_zone_end(struct event evt) { 2163 | #pragma pack(push, 1) 2164 | struct network_zone_end { 2165 | char unsigned type; 2166 | long long timestamp; 2167 | }; 2168 | _Static_assert(9 == sizeof(struct network_zone_end), "incorrect size"); 2169 | #pragma pack(pop) 2170 | 2171 | long long timestamp = evt.zone_end.timestamp - utracy.data.cur_thread.timestamp; 2172 | utracy.data.cur_thread.timestamp = evt.zone_end.timestamp; 2173 | 2174 | struct network_zone_end msg = { 2175 | .type = utracy.protocol.zone_end, 2176 | .timestamp = timestamp 2177 | }; 2178 | 2179 | if(0 != utracy_write_packet(&msg, sizeof(msg))) { 2180 | LOG_DEBUG_ERROR; 2181 | return -1; 2182 | } 2183 | 2184 | return 0; 2185 | } 2186 | 2187 | UTRACY_INTERNAL UTRACY_INLINE 2188 | int utracy_write_zone_color(struct event evt) { 2189 | #pragma pack(push, 1) 2190 | struct network_zone_color { 2191 | char unsigned type; 2192 | char unsigned r; 2193 | char unsigned g; 2194 | char unsigned b; 2195 | }; 2196 | _Static_assert(4 == sizeof(struct network_zone_color), "incorrect size"); 2197 | #pragma pack(pop) 2198 | 2199 | struct network_zone_color msg = { 2200 | .type = utracy.protocol.zone_color, 2201 | .r = (evt.zone_color.color >> 0) & 0xFF, 2202 | .g = (evt.zone_color.color >> 8) & 0xFF, 2203 | .b = (evt.zone_color.color >> 16) & 0xFF 2204 | }; 2205 | 2206 | if(0 != utracy_write_packet(&msg, sizeof(msg))) { 2207 | LOG_DEBUG_ERROR; 2208 | return -1; 2209 | } 2210 | 2211 | return 0; 2212 | } 2213 | 2214 | UTRACY_INTERNAL UTRACY_INLINE 2215 | int utracy_write_frame_mark(struct event evt) { 2216 | #pragma pack(push, 1) 2217 | struct network_frame_mark { 2218 | char unsigned type; 2219 | long long timestamp; 2220 | long long unsigned name; 2221 | }; 2222 | _Static_assert(17 == sizeof(struct network_frame_mark), "incorrect size"); 2223 | #pragma pack(pop) 2224 | 2225 | struct network_frame_mark msg = { 2226 | .type = utracy.protocol.framemark, 2227 | .timestamp = evt.frame_mark.timestamp, 2228 | .name = (uintptr_t) evt.frame_mark.name 2229 | }; 2230 | 2231 | if(0 != utracy_write_packet(&msg, sizeof(msg))) { 2232 | LOG_DEBUG_ERROR; 2233 | return -1; 2234 | } 2235 | 2236 | return 0; 2237 | } 2238 | 2239 | UTRACY_INTERNAL UTRACY_INLINE 2240 | int utracy_write_srcloc(struct utracy_source_location const *const srcloc) { 2241 | #pragma pack(push, 1) 2242 | struct network_srcloc { 2243 | char unsigned type; 2244 | long long unsigned name; 2245 | long long unsigned function; 2246 | long long unsigned file; 2247 | int unsigned line; 2248 | char unsigned r; 2249 | char unsigned g; 2250 | char unsigned b; 2251 | }; 2252 | _Static_assert(32 == sizeof(struct network_srcloc), "incorrect size"); 2253 | #pragma pack(pop) 2254 | 2255 | struct network_srcloc msg = { 2256 | .type = utracy.protocol.response_source_location, 2257 | .name = (uintptr_t) srcloc->name, 2258 | .function = (uintptr_t) srcloc->function, 2259 | .file = (uintptr_t) srcloc->file, 2260 | .line = srcloc->line, 2261 | .r = (srcloc->color >> 0) & 0xFF, 2262 | .g = (srcloc->color >> 8) & 0xFF, 2263 | .b = (srcloc->color >> 16) & 0xFF 2264 | }; 2265 | 2266 | if(0 != utracy_write_packet(&msg, sizeof(msg))) { 2267 | LOG_DEBUG_ERROR; 2268 | return -1; 2269 | } 2270 | 2271 | return 0; 2272 | } 2273 | 2274 | UTRACY_INTERNAL UTRACY_INLINE 2275 | int utracy_write_stringdata(char unsigned type, char const *const str, long long unsigned ptr) { 2276 | #pragma pack(push, 1) 2277 | struct network_query_stringdata { 2278 | char unsigned type; 2279 | long long unsigned ptr; 2280 | short unsigned len; 2281 | char str[]; 2282 | }; 2283 | _Static_assert(11 == sizeof(struct network_query_stringdata), "incorrect size"); 2284 | #pragma pack(pop) 2285 | 2286 | short unsigned len = (short unsigned) strlen(str); 2287 | size_t size = sizeof(struct network_query_stringdata) + len; 2288 | 2289 | static char buf[sizeof(struct network_query_stringdata) + 65536]; 2290 | struct network_query_stringdata *msg = (struct network_query_stringdata *) buf; 2291 | 2292 | msg->type = type; 2293 | msg->ptr = ptr; 2294 | msg->len = len; 2295 | (void) UTRACY_MEMCPY(msg->str, str, len); 2296 | 2297 | if(0 != utracy_write_packet(msg, size)) { 2298 | LOG_DEBUG_ERROR; 2299 | return -1; 2300 | } 2301 | 2302 | return 0; 2303 | } 2304 | 2305 | UTRACY_INTERNAL UTRACY_INLINE 2306 | int utracy_write_symbol_code(void) { 2307 | char unsigned response = utracy.protocol.response_symbol_code_unavail; 2308 | 2309 | if(0 != utracy_write_packet(&response, sizeof(response))) { 2310 | LOG_DEBUG_ERROR; 2311 | return -1; 2312 | } 2313 | 2314 | return 0; 2315 | } 2316 | 2317 | UTRACY_INTERNAL UTRACY_INLINE 2318 | int utracy_write_source_code(int unsigned id) { 2319 | #pragma pack(push, 1) 2320 | struct network_response_source_code { 2321 | char unsigned type; 2322 | int unsigned id; 2323 | }; 2324 | _Static_assert(5 == sizeof(struct network_response_source_code), "incorrect size"); 2325 | #pragma pack(pop) 2326 | 2327 | switch(utracy.protocol.version) { 2328 | case UTRACY_PROTOCOL_0_8_1: 2329 | case UTRACY_PROTOCOL_0_8_2:; 2330 | char unsigned response = utracy.protocol.response_source_code_unavail; 2331 | 2332 | if(0 != utracy_write_packet(&response, sizeof(response))) { 2333 | LOG_DEBUG_ERROR; 2334 | return -1; 2335 | } 2336 | break; 2337 | 2338 | case UTRACY_PROTOCOL_0_9_0: 2339 | case UTRACY_PROTOCOL_0_10_0: 2340 | case UTRACY_PROTOCOL_0_11_0: 2341 | case UTRACY_PROTOCOL_0_11_1:; 2342 | struct network_response_source_code msg = { 2343 | .type = utracy.protocol.response_source_code_unavail, 2344 | .id = id 2345 | }; 2346 | 2347 | if(0 != utracy_write_packet(&msg, sizeof(msg))) { 2348 | LOG_DEBUG_ERROR; 2349 | return -1; 2350 | } 2351 | break; 2352 | } 2353 | 2354 | return 0; 2355 | } 2356 | 2357 | UTRACY_INTERNAL UTRACY_INLINE 2358 | int utracy_write_data_part(void) { 2359 | char unsigned response = utracy.protocol.response_server_query_noop; 2360 | 2361 | if(0 != utracy_write_packet(&response, sizeof(response))) { 2362 | LOG_DEBUG_ERROR; 2363 | return -1; 2364 | } 2365 | 2366 | return 0; 2367 | } 2368 | 2369 | UTRACY_INTERNAL 2370 | int utracy_consume_request(void) { 2371 | #pragma pack(push, 1) 2372 | struct network_recv_request { 2373 | char unsigned type; 2374 | long long unsigned ptr; 2375 | int unsigned extra; 2376 | }; 2377 | _Static_assert(13 == sizeof(struct network_recv_request), "incorrect size"); 2378 | #pragma pack(pop) 2379 | 2380 | struct network_recv_request req; 2381 | if(0 != utracy_client_recv(&req, sizeof(req))) { 2382 | LOG_DEBUG_ERROR; 2383 | return -1; 2384 | } 2385 | 2386 | if(req.type == utracy.protocol.query_string) { 2387 | if(0 != utracy_write_stringdata(utracy.protocol.response_string_data, (char *) (uintptr_t) req.ptr, req.ptr)) { 2388 | LOG_DEBUG_ERROR; 2389 | return -1; 2390 | } 2391 | 2392 | } else if(req.type == utracy.protocol.query_thread_string) { 2393 | if(0 != utracy_write_stringdata(utracy.protocol.response_thread_name, "main", req.ptr)) { 2394 | LOG_DEBUG_ERROR; 2395 | return -1; 2396 | } 2397 | 2398 | } else if(req.type == utracy.protocol.query_source_location) { 2399 | if(0 != utracy_write_srcloc((struct utracy_source_location *) (uintptr_t) req.ptr)) { 2400 | LOG_DEBUG_ERROR; 2401 | return -1; 2402 | } 2403 | 2404 | } else if(req.type == utracy.protocol.query_symbol_code) { 2405 | if(0 != utracy_write_symbol_code()) { 2406 | LOG_DEBUG_ERROR; 2407 | return -1; 2408 | } 2409 | 2410 | } else if(req.type == utracy.protocol.query_source_code) { 2411 | if(0 != utracy_write_source_code((int unsigned) req.ptr)) { 2412 | LOG_DEBUG_ERROR; 2413 | return -1; 2414 | } 2415 | 2416 | } else if(req.type == utracy.protocol.query_data_transfer || req.type == utracy.protocol.query_data_transfer_part) { 2417 | if(0 != utracy_write_data_part()) { 2418 | LOG_DEBUG_ERROR; 2419 | return -1; 2420 | } 2421 | } 2422 | 2423 | return 0; 2424 | } 2425 | 2426 | UTRACY_INTERNAL UTRACY_INLINE 2427 | int utracy_switch_thread_context(int unsigned tid) { 2428 | if(tid != utracy.data.cur_thread.tid) { 2429 | utracy.data.cur_thread.tid = tid; 2430 | utracy.data.cur_thread.timestamp = 0ll; 2431 | 2432 | return utracy_write_server_context(tid); 2433 | } 2434 | 2435 | return 0; 2436 | } 2437 | 2438 | static int unsigned hacky_proc_stack; 2439 | 2440 | UTRACY_INTERNAL 2441 | int utracy_consume_queue(void) { 2442 | struct event evt; 2443 | 2444 | if(1 != utracy.sock.connected) { 2445 | while(0 == event_queue_pop(&evt)); 2446 | return 0; 2447 | } 2448 | 2449 | while(0 == event_queue_pop(&evt)) { 2450 | switch(evt.type) { 2451 | case UTRACY_EVT_ZONEBEGIN: 2452 | if(0 != utracy_switch_thread_context(evt.zone_begin.tid)) { 2453 | LOG_DEBUG_ERROR; 2454 | return -1; 2455 | } 2456 | 2457 | if(0 != utracy_write_zone_begin(evt)) { 2458 | LOG_DEBUG_ERROR; 2459 | return -1; 2460 | } 2461 | 2462 | hacky_proc_stack++; 2463 | break; 2464 | 2465 | case UTRACY_EVT_ZONEEND: 2466 | if(0 < hacky_proc_stack) { 2467 | hacky_proc_stack--; 2468 | } else { 2469 | break; 2470 | } 2471 | 2472 | if(0 != utracy_switch_thread_context(evt.zone_end.tid)) { 2473 | LOG_DEBUG_ERROR; 2474 | return -1; 2475 | } 2476 | 2477 | if(0 != utracy_write_zone_end(evt)) { 2478 | LOG_DEBUG_ERROR; 2479 | return -1; 2480 | } 2481 | break; 2482 | 2483 | case UTRACY_EVT_ZONECOLOR: 2484 | if(!hacky_proc_stack) { 2485 | break; 2486 | } 2487 | 2488 | if(0 != utracy_switch_thread_context(evt.zone_color.tid)) { 2489 | LOG_DEBUG_ERROR; 2490 | return -1; 2491 | } 2492 | 2493 | if(0 != utracy_write_zone_color(evt)) { 2494 | LOG_DEBUG_ERROR; 2495 | return -1; 2496 | } 2497 | break; 2498 | 2499 | case UTRACY_EVT_FRAMEMARKMSG: 2500 | if(0 != utracy_write_frame_mark(evt)) { 2501 | LOG_DEBUG_ERROR; 2502 | return -1; 2503 | } 2504 | break; 2505 | 2506 | default: 2507 | LOG_DEBUG_ERROR; 2508 | return -1; 2509 | } 2510 | } 2511 | 2512 | return 0; 2513 | } 2514 | 2515 | UTRACY_INTERNAL 2516 | int utracy_server_pump(void) { 2517 | if(0 != utracy_consume_queue()) { 2518 | LOG_DEBUG_ERROR; 2519 | return -1; 2520 | } 2521 | 2522 | if(1 != utracy.sock.connected) { 2523 | return -2; 2524 | } 2525 | 2526 | #if defined(UTRACY_WINDOWS) 2527 | WSAPOLLFD descriptor = { 2528 | .fd = utracy.sock.client, 2529 | .events = POLLRDNORM, 2530 | .revents = 0 2531 | }; 2532 | 2533 | int polled = WSAPoll(&descriptor, 1, 1); 2534 | 2535 | #elif defined(UTRACY_LINUX) 2536 | struct pollfd descriptor = { 2537 | .fd = utracy.sock.client, 2538 | .events = POLLRDNORM, 2539 | .revents = 0 2540 | }; 2541 | 2542 | int polled = poll(&descriptor, 1, 1); 2543 | 2544 | #endif 2545 | 2546 | if(0 < polled) { 2547 | if(0 != utracy_consume_request()) { 2548 | LOG_DEBUG_ERROR; 2549 | return -1; 2550 | } 2551 | 2552 | } else if(-1 == polled) { 2553 | LOG_DEBUG_ERROR; 2554 | return -1; 2555 | } 2556 | 2557 | long long now = utracy_tsc(); 2558 | if(now - utracy.data.prev_commit >= UTRACY_LATENCY) { 2559 | if(0 != utracy_commit()) { 2560 | LOG_DEBUG_ERROR; 2561 | return -1; 2562 | } 2563 | } 2564 | 2565 | return 0; 2566 | } 2567 | 2568 | UTRACY_INTERNAL 2569 | int utracy_client_negotiate(void) { 2570 | char handshake[8]; 2571 | if(0 != utracy_client_recv(handshake, sizeof(handshake))) { 2572 | LOG_DEBUG_ERROR; 2573 | return -1; 2574 | } 2575 | 2576 | if(0 != UTRACY_MEMCMP(handshake, "TracyPrf", 8)) { 2577 | LOG_DEBUG_ERROR; 2578 | return -1; 2579 | } 2580 | 2581 | int unsigned protocol; 2582 | if(0 != utracy_client_recv(&protocol, sizeof(protocol))) { 2583 | LOG_DEBUG_ERROR; 2584 | return -1; 2585 | } 2586 | 2587 | if(0 != utracy_protocol_init(protocol)) { 2588 | LOG_DEBUG_ERROR; 2589 | 2590 | /* protocol mismatch */ 2591 | char unsigned response = 2; 2592 | if(0 != utracy_client_send(&response, sizeof(response))) { 2593 | LOG_DEBUG_ERROR; 2594 | } 2595 | 2596 | return -1; 2597 | } 2598 | 2599 | /* success */ 2600 | char unsigned response = 1; 2601 | if(0 != utracy_client_send(&response, sizeof(response))) { 2602 | LOG_DEBUG_ERROR; 2603 | return -1; 2604 | } 2605 | 2606 | #pragma pack(push, 1) 2607 | struct network_welcome { 2608 | double multiplier; 2609 | long long init_begin; 2610 | long long init_end; 2611 | long long delay; 2612 | long long resolution; 2613 | long long epoch; 2614 | long long exec_time; 2615 | long long pid; 2616 | long long sampling_period; 2617 | char unsigned flags; 2618 | char unsigned cpu_arch; 2619 | char cpu_manufacturer[12]; 2620 | int unsigned cpu_id; 2621 | char program_name[64]; 2622 | char host_info[1024]; 2623 | }; 2624 | _Static_assert(1178 == sizeof(struct network_welcome), "incorrect size"); 2625 | #pragma pack(pop) 2626 | 2627 | struct network_welcome welcome = { 2628 | .multiplier = utracy.info.multiplier, 2629 | .init_begin = utracy.info.init_begin, 2630 | .init_end = utracy.info.init_end, 2631 | .delay = utracy.info.delay, 2632 | .resolution = utracy.info.resolution, 2633 | .epoch = utracy.info.epoch, 2634 | .exec_time = utracy.info.exec_time, 2635 | .pid = 0, 2636 | .sampling_period = 0, 2637 | .flags = 1, 2638 | .cpu_arch = 0, 2639 | .cpu_manufacturer = "???", 2640 | .cpu_id = 0, 2641 | .program_name = "DREAMDAEMON", 2642 | .host_info = "???" 2643 | }; 2644 | 2645 | if(0 != utracy_client_send(&welcome, sizeof(welcome))) { 2646 | LOG_DEBUG_ERROR; 2647 | return -1; 2648 | } 2649 | 2650 | #pragma pack(push, 1) 2651 | struct network_ondemand { 2652 | long long unsigned frames; 2653 | long long unsigned timestamp; 2654 | }; 2655 | _Static_assert(16 == sizeof(struct network_ondemand), "incorrect size"); 2656 | #pragma pack(pop) 2657 | 2658 | struct network_ondemand ondemand = { 2659 | .frames = 0ull, 2660 | .timestamp = utracy_tsc() 2661 | }; 2662 | 2663 | if(0 != utracy_client_send(&ondemand, sizeof(ondemand))) { 2664 | LOG_DEBUG_ERROR; 2665 | return -1; 2666 | } 2667 | 2668 | return 0; 2669 | } 2670 | 2671 | UTRACY_INTERNAL 2672 | int utracy_client_disconnect(void) { 2673 | utracy.sock.connected = 0; 2674 | 2675 | #if defined(UTRACY_WINDOWS) 2676 | if(0 != shutdown(utracy.sock.client, SD_SEND)) { 2677 | LOG_DEBUG_ERROR; 2678 | } 2679 | 2680 | if(0 != closesocket(utracy.sock.client)) { 2681 | LOG_DEBUG_ERROR; 2682 | return -1; 2683 | } 2684 | 2685 | #elif defined(UTRACY_LINUX) 2686 | if(0 != close(utracy.sock.client)) { 2687 | LOG_DEBUG_ERROR; 2688 | return -1; 2689 | } 2690 | 2691 | #endif 2692 | 2693 | return 0; 2694 | } 2695 | 2696 | UTRACY_INTERNAL 2697 | #if defined(UTRACY_WINDOWS) 2698 | DWORD WINAPI utracy_server_thread_start(PVOID user) { 2699 | #elif defined(UTRACY_LINUX) 2700 | void *utracy_server_thread_start(void *user) { 2701 | #endif 2702 | (void) user; 2703 | 2704 | do { 2705 | if(0 == utracy.sock.connected) { 2706 | #if defined(UTRACY_WINDOWS) 2707 | WSAPOLLFD descriptor = { 2708 | .fd = utracy.sock.server, 2709 | .events = POLLRDNORM, 2710 | .revents = 0 2711 | }; 2712 | 2713 | int polled = WSAPoll(&descriptor, 1, 1); 2714 | 2715 | #elif defined(UTRACY_LINUX) 2716 | struct pollfd descriptor = { 2717 | .fd = utracy.sock.server, 2718 | .events = POLLRDNORM, 2719 | .revents = 0 2720 | }; 2721 | 2722 | int polled = poll(&descriptor, 1, 1); 2723 | 2724 | #endif 2725 | 2726 | if(0 < polled) { 2727 | if(0 != utracy_client_accept()) { 2728 | LOG_DEBUG_ERROR; 2729 | continue; 2730 | } 2731 | 2732 | (void) UTRACY_MEMSET(&utracy.data, 0, sizeof(utracy.data)); 2733 | LZ4_resetStream_fast(&utracy.data.stream); 2734 | hacky_proc_stack = 0; 2735 | 2736 | if(0 != utracy_client_negotiate()) { 2737 | LOG_DEBUG_ERROR; 2738 | (void) utracy_client_disconnect(); 2739 | continue; 2740 | } 2741 | } 2742 | } 2743 | 2744 | while(0 == utracy_server_pump()); 2745 | 2746 | if(1 == utracy.sock.connected) { 2747 | (void) utracy_client_disconnect(); 2748 | } 2749 | } while(1); 2750 | 2751 | #if defined(UTRACY_WINDOWS) 2752 | ExitThread(0); 2753 | #elif defined(UTRACY_LINUX) 2754 | pthread_exit(NULL); 2755 | #endif 2756 | } 2757 | 2758 | /* byond hooks */ 2759 | UTRACY_INTERNAL 2760 | struct object UTRACY_WINDOWS_CDECL UTRACY_LINUX_REGPARM(3) exec_proc(struct proc *proc) { 2761 | if(likely(proc->procdef < 0x14000)) { 2762 | utracy_emit_zone_begin(srclocs + proc->procdef); 2763 | 2764 | /* procs with pre-existing contexts are resuming from sleep */ 2765 | if(unlikely(proc->ctx != NULL)) { 2766 | utracy_emit_zone_color(0xAF4444); 2767 | } 2768 | 2769 | struct object result = byond.orig_exec_proc(proc); 2770 | 2771 | utracy_emit_zone_end(); 2772 | 2773 | return result; 2774 | } 2775 | 2776 | return byond.orig_exec_proc(proc); 2777 | } 2778 | 2779 | UTRACY_INTERNAL 2780 | int UTRACY_WINDOWS_STDCALL UTRACY_LINUX_CDECL server_tick(void) { 2781 | static struct utracy_source_location const srcloc = { 2782 | .name = NULL, 2783 | .function = "ServerTick", 2784 | .file = __FILE__, 2785 | .line = __LINE__, 2786 | .color = 0x44AF44 2787 | }; 2788 | 2789 | /* server tick is the end of a frame and the beginning of the next frame */ 2790 | utracy_emit_frame_mark(NULL); 2791 | 2792 | utracy_emit_zone_begin(&srcloc); 2793 | 2794 | int interval = byond.orig_server_tick(); 2795 | 2796 | utracy_emit_zone_end(); 2797 | 2798 | return interval; 2799 | } 2800 | 2801 | UTRACY_INTERNAL 2802 | void UTRACY_WINDOWS_CDECL UTRACY_LINUX_CDECL send_maps(void) { 2803 | static struct utracy_source_location const srcloc = { 2804 | .name = NULL, 2805 | .function = "SendMaps", 2806 | .file = __FILE__, 2807 | .line = __LINE__, 2808 | .color = 0x44AF44 2809 | }; 2810 | 2811 | utracy_emit_zone_begin(&srcloc); 2812 | 2813 | byond.orig_send_maps(); 2814 | 2815 | utracy_emit_zone_end(); 2816 | } 2817 | 2818 | /* hooking */ 2819 | UTRACY_INTERNAL 2820 | void *hook(char *const restrict dst, char *const restrict src, char unsigned size, char *trampoline) { 2821 | char unsigned jmp[] = { 2822 | 0xE9, 0x00, 0x00, 0x00, 0x00 2823 | }; 2824 | 2825 | uintptr_t jmp_from = (uintptr_t) trampoline + size + sizeof(jmp); 2826 | uintptr_t jmp_to = (uintptr_t) src + size; 2827 | uintptr_t offset = jmp_to - jmp_from; 2828 | (void) UTRACY_MEMCPY(jmp + 1, &offset, sizeof(offset)); 2829 | (void) UTRACY_MEMCPY(trampoline, src, size); 2830 | (void) UTRACY_MEMCPY(trampoline + size, jmp, sizeof(jmp)); 2831 | 2832 | jmp_from = (uintptr_t) src + sizeof(jmp); 2833 | jmp_to = (uintptr_t) dst; 2834 | offset = jmp_to - jmp_from; 2835 | 2836 | #if defined(UTRACY_WINDOWS) 2837 | DWORD old_protect; 2838 | if(0 == VirtualProtect(src, size, PAGE_READWRITE, &old_protect)) { 2839 | LOG_DEBUG_ERROR; 2840 | return NULL; 2841 | } 2842 | 2843 | #elif defined(UTRACY_LINUX) 2844 | if(0 != mprotect(UTRACY_ALIGN_DOWN(src, UTRACY_PAGE_SIZE), UTRACY_PAGE_SIZE, PROT_WRITE | PROT_READ)) { 2845 | LOG_DEBUG_ERROR; 2846 | return NULL; 2847 | } 2848 | 2849 | #endif 2850 | 2851 | (void) UTRACY_MEMCPY(jmp + 1, &offset, sizeof(offset)); 2852 | (void) UTRACY_MEMCPY(src, &jmp, sizeof(jmp)); 2853 | 2854 | if(size > sizeof(jmp)) { 2855 | for(size_t i=0; i<(size - sizeof(jmp)); i++) { 2856 | char unsigned nop = 0x90; 2857 | (void) UTRACY_MEMCPY(src + sizeof(jmp) + i, &nop, 1); 2858 | } 2859 | } 2860 | 2861 | #if defined(UTRACY_WINDOWS) 2862 | if(0 == VirtualProtect(src, size, old_protect, &old_protect)) { 2863 | LOG_DEBUG_ERROR; 2864 | return NULL; 2865 | } 2866 | 2867 | #elif defined(UTRACY_LINUX) 2868 | if(0 != mprotect(UTRACY_ALIGN_DOWN(src, UTRACY_PAGE_SIZE), UTRACY_PAGE_SIZE, PROT_READ | PROT_EXEC)) { 2869 | LOG_DEBUG_ERROR; 2870 | return NULL; 2871 | } 2872 | 2873 | #endif 2874 | 2875 | return trampoline; 2876 | } 2877 | 2878 | #if defined(UTRACY_WINDOWS) 2879 | # define BYOND_MAX_BUILD 1647 2880 | # define BYOND_MIN_BUILD 1543 2881 | # define BYOND_VERSION_ADJUSTED(a) ((a) - BYOND_MIN_BUILD) 2882 | 2883 | static int unsigned const byond_offsets[][11] = { 2884 | /* strings strings_len miscs miscs_len procdefs procdefs_len procdef exec_proc server_tick send_maps prologue */ 2885 | [BYOND_VERSION_ADJUSTED(1543)] = {0x0035FC58, 0x0035FC5C, 0x0035FC68, 0x0035FC6C, 0x0035FC78, 0x0035FC7C, 0x00180024, 0x001003B0, 0x001C7D20, 0x00187C80, 0x00050B06}, 2886 | [BYOND_VERSION_ADJUSTED(1544)] = {0x00360C58, 0x00360C5C, 0x00360C68, 0x00360C6C, 0x00360C78, 0x00360C7C, 0x00180024, 0x00100A10, 0x001C8420, 0x00188220, 0x00050B06}, 2887 | [BYOND_VERSION_ADJUSTED(1545)] = {0x00360C60, 0x00360C64, 0x00360C70, 0x00360C74, 0x00360C80, 0x00360C84, 0x00180024, 0x00100980, 0x001C8400, 0x00188190, 0x00050B06}, 2888 | [BYOND_VERSION_ADJUSTED(1546)] = {0x00360C60, 0x00360C64, 0x00360C70, 0x00360C74, 0x00360C80, 0x00360C84, 0x00180024, 0x00100830, 0x001C8280, 0x001880C0, 0x00050606}, 2889 | [BYOND_VERSION_ADJUSTED(1547)] = {0x00362C68, 0x00362C6C, 0x00362C78, 0x00362C7C, 0x00362C88, 0x00362C8C, 0x00180024, 0x00101210, 0x001C9320, 0x001891F0, 0x00050606}, 2890 | [BYOND_VERSION_ADJUSTED(1548)] = {0x00362C48, 0x00362C4C, 0x00362C58, 0x00362C5C, 0x00362C68, 0x00362C6C, 0x00180024, 0x00101640, 0x001C96D0, 0x00188E80, 0x00050606}, 2891 | [BYOND_VERSION_ADJUSTED(1549)] = {0x00368DD4, 0x00368DD8, 0x00368DEC, 0x00368DF0, 0x00368E00, 0x00368E04, 0x00180024, 0x001023B0, 0x001CB0A0, 0x0018AD80, 0x00050606}, 2892 | [BYOND_VERSION_ADJUSTED(1550)] = {0x0036903C, 0x00369040, 0x0036904C, 0x00369050, 0x0036905C, 0x00369060, 0x00180024, 0x00102710, 0x001CB710, 0x0018B0B0, 0x00050606}, 2893 | [BYOND_VERSION_ADJUSTED(1551)] = {0x00369034, 0x00369038, 0x00369044, 0x00369048, 0x00369054, 0x00369058, 0x00180024, 0x00102C30, 0x001CB830, 0x0018B120, 0x00050606}, 2894 | [BYOND_VERSION_ADJUSTED(1552)] = {0x0036A054, 0x0036A058, 0x0036A064, 0x0036A068, 0x0036A074, 0x0036A078, 0x00180024, 0x00102DE0, 0x001CBDE0, 0x0018B6B0, 0x00050606}, 2895 | [BYOND_VERSION_ADJUSTED(1553)] = {0x0036E234, 0x0036E238, 0x0036E244, 0x0036E248, 0x0036E254, 0x0036E258, 0x00180024, 0x00104FF0, 0x001CF780, 0x0018DE50, 0x00050606}, 2896 | [BYOND_VERSION_ADJUSTED(1554)] = {0x0036DFF8, 0x0036DFFC, 0x0036E008, 0x0036E00C, 0x0036E018, 0x0036E01C, 0x00180024, 0x00104ED0, 0x001CF650, 0x0018E000, 0x00050606}, 2897 | [BYOND_VERSION_ADJUSTED(1555)] = {0x0036E0B0, 0x0036E0B4, 0x0036E0C0, 0x0036E0C4, 0x0036E0D0, 0x0036E0D4, 0x00180024, 0x001064F0, 0x001CFD80, 0x0018EEB0, 0x00050606}, 2898 | [BYOND_VERSION_ADJUSTED(1556)] = {0x0036E0AC, 0x0036E0B0, 0x0036E0BC, 0x0036E0C0, 0x0036E0CC, 0x0036E0D0, 0x00180024, 0x00106560, 0x001CFD80, 0x0018EEE0, 0x00050606}, 2899 | [BYOND_VERSION_ADJUSTED(1557)] = {0x0036E0C0, 0x0036E0C4, 0x0036E0D0, 0x0036E0D4, 0x0036E0E0, 0x0036E0E4, 0x00180024, 0x001063B0, 0x001CFB60, 0x0018EC70, 0x00050606}, 2900 | [BYOND_VERSION_ADJUSTED(1558)] = {0x0036F4F4, 0x0036F4F8, 0x0036F504, 0x0036F508, 0x0036F514, 0x0036F518, 0x00180024, 0x00106DE0, 0x001D1160, 0x0018FD80, 0x00050606}, 2901 | [BYOND_VERSION_ADJUSTED(1559)] = {0x0036F4F4, 0x0036F4F8, 0x0036F504, 0x0036F508, 0x0036F514, 0x0036F518, 0x00180024, 0x00106DE0, 0x001D1160, 0x0018FD80, 0x00050606}, 2902 | [BYOND_VERSION_ADJUSTED(1560)] = {0x0036F4F4, 0x0036F4F8, 0x0036F504, 0x0036F508, 0x0036F514, 0x0036F518, 0x00180024, 0x00106AF0, 0x001D1120, 0x0018FA80, 0x00050606}, 2903 | [BYOND_VERSION_ADJUSTED(1561)] = {0x0036F4F4, 0x0036F4F8, 0x0036F504, 0x0036F508, 0x0036F514, 0x0036F518, 0x00180024, 0x00106AF0, 0x001D1120, 0x0018FA80, 0x00050606}, 2904 | [BYOND_VERSION_ADJUSTED(1562)] = {0x0036F538, 0x0036F53C, 0x0036F548, 0x0036F54C, 0x0036F558, 0x0036F55C, 0x00180024, 0x00106960, 0x001D0F00, 0x0018F780, 0x00050606}, 2905 | [BYOND_VERSION_ADJUSTED(1563)] = {0x0036F538, 0x0036F53C, 0x0036F548, 0x0036F54C, 0x0036F558, 0x0036F55C, 0x00180024, 0x001066A0, 0x001D1160, 0x0018F660, 0x00050606}, 2906 | [BYOND_VERSION_ADJUSTED(1564)] = {0x0036F538, 0x0036F53C, 0x0036F548, 0x0036F54C, 0x0036F558, 0x0036F55C, 0x00180024, 0x00106310, 0x001D0F20, 0x0018F1E0, 0x00050606}, 2907 | [BYOND_VERSION_ADJUSTED(1565)] = {0x00371538, 0x0037153C, 0x00371548, 0x0037154C, 0x00371558, 0x0037155C, 0x00180024, 0x00106960, 0x001D15A0, 0x0018FCC0, 0x00050606}, 2908 | [BYOND_VERSION_ADJUSTED(1566)] = {0x00371538, 0x0037153C, 0x00371548, 0x0037154C, 0x00371558, 0x0037155C, 0x00180024, 0x00106160, 0x001D0A70, 0x0018EF80, 0x00050606}, 2909 | [BYOND_VERSION_ADJUSTED(1567)] = {0x00370548, 0x0037054C, 0x00370560, 0x00370564, 0x00370570, 0x00370574, 0x00180024, 0x00106220, 0x001D0B00, 0x0018F470, 0x00050606}, 2910 | [BYOND_VERSION_ADJUSTED(1568)] = {0x00370548, 0x0037054C, 0x00370560, 0x00370564, 0x00370570, 0x00370574, 0x00180024, 0x00106220, 0x001D0B30, 0x0018F470, 0x00050606}, 2911 | [BYOND_VERSION_ADJUSTED(1569)] = {0x00370548, 0x0037054C, 0x00370560, 0x00370564, 0x00370570, 0x00370574, 0x00180024, 0x00106220, 0x001D0B40, 0x0018F500, 0x00050606}, 2912 | [BYOND_VERSION_ADJUSTED(1570)] = {0x00371548, 0x0037154C, 0x00371558, 0x0037155C, 0x00371568, 0x0037156C, 0x00180024, 0x00106560, 0x001D0BF0, 0x0018F8F0, 0x00050606}, 2913 | [BYOND_VERSION_ADJUSTED(1571)] = {0x00371548, 0x0037154C, 0x00371558, 0x0037155C, 0x00371568, 0x0037156C, 0x00180024, 0x001061D0, 0x001D0A70, 0x0018F500, 0x00050606}, 2914 | [BYOND_VERSION_ADJUSTED(1572)] = {0x00371540, 0x00371544, 0x00371550, 0x00371554, 0x00371560, 0x00371564, 0x00180024, 0x001066A0, 0x001D0F60, 0x0018FCC0, 0x00050606}, 2915 | [BYOND_VERSION_ADJUSTED(1573)] = {0x00371608, 0x0037160C, 0x00371618, 0x0037161C, 0x00371628, 0x0037162C, 0x00180024, 0x00106BD0, 0x001D13C0, 0x0018FC40, 0x00050606}, 2916 | [BYOND_VERSION_ADJUSTED(1574)] = {0x00371550, 0x00371554, 0x00371560, 0x00371564, 0x00371570, 0x00371574, 0x00180024, 0x001065A0, 0x001D10E0, 0x0018FDC0, 0x00050606}, 2917 | [BYOND_VERSION_ADJUSTED(1575)] = {0x00371550, 0x00371554, 0x00371560, 0x00371564, 0x00371570, 0x00371574, 0x00180024, 0x001065A0, 0x001D10E0, 0x0018FDC0, 0x00050606}, 2918 | [BYOND_VERSION_ADJUSTED(1576)] = {0x003745BC, 0x003745C0, 0x003745CC, 0x003745D0, 0x003745DC, 0x003745E0, 0x00180024, 0x001087B0, 0x001D30A0, 0x00191C60, 0x00050606}, 2919 | [BYOND_VERSION_ADJUSTED(1577)] = {0x003745BC, 0x003745C0, 0x003745CC, 0x003745D0, 0x003745DC, 0x003745E0, 0x00180024, 0x00107FC0, 0x001D2C90, 0x00191A60, 0x00050606}, 2920 | [BYOND_VERSION_ADJUSTED(1578)] = {0x003745BC, 0x003745C0, 0x003745CC, 0x003745D0, 0x003745DC, 0x003745E0, 0x00180024, 0x001083B0, 0x001D2E90, 0x00191910, 0x00050606}, 2921 | [BYOND_VERSION_ADJUSTED(1579)] = {0x003745C8, 0x003745CC, 0x003745D8, 0x003745DC, 0x003745E8, 0x003745EC, 0x00180024, 0x00108C20, 0x001D3940, 0x001925C0, 0x00050606}, 2922 | [BYOND_VERSION_ADJUSTED(1580)] = {0x003745C8, 0x003745CC, 0x003745D8, 0x003745DC, 0x003745E8, 0x003745EC, 0x00180024, 0x00108BD0, 0x001D38B0, 0x00192520, 0x00050606}, 2923 | [BYOND_VERSION_ADJUSTED(1581)] = {0x003745C8, 0x003745CC, 0x003745D8, 0x003745DC, 0x003745E8, 0x003745EC, 0x00180024, 0x001086A0, 0x001D3780, 0x001923A0, 0x00050606}, 2924 | [BYOND_VERSION_ADJUSTED(1582)] = {0x003745C8, 0x003745CC, 0x003745D8, 0x003745DC, 0x003745E8, 0x003745EC, 0x00180024, 0x001087B0, 0x001D3A40, 0x00191FF0, 0x00050606}, 2925 | [BYOND_VERSION_ADJUSTED(1583)] = {0x003755C8, 0x003755CC, 0x003755D8, 0x003755DC, 0x003755E8, 0x003755EC, 0x00180024, 0x00108240, 0x001D33F0, 0x001919E0, 0x00050606}, 2926 | [BYOND_VERSION_ADJUSTED(1584)] = {0x003764B4, 0x003764B8, 0x003764C4, 0x003764C8, 0x003764D4, 0x003764D8, 0x00180024, 0x00108460, 0x001D3A40, 0x001922C0, 0x00050606}, 2927 | [BYOND_VERSION_ADJUSTED(1585)] = {0x003774AC, 0x003774B0, 0x003774BC, 0x003774C0, 0x003774CC, 0x003774D0, 0x00180024, 0x001094D0, 0x001D49E0, 0x00192D80, 0x00050606}, 2928 | [BYOND_VERSION_ADJUSTED(1586)] = {0x00378524, 0x00378528, 0x00378534, 0x00378538, 0x00378544, 0x00378548, 0x00180024, 0x00109AA0, 0x001D5160, 0x00193370, 0x00050606}, 2929 | [BYOND_VERSION_ADJUSTED(1587)] = {0x00378524, 0x00378528, 0x00378534, 0x00378538, 0x00378544, 0x00378548, 0x00180024, 0x00109AA0, 0x001D5160, 0x00193370, 0x00050606}, 2930 | [BYOND_VERSION_ADJUSTED(1588)] = {0x00378524, 0x00378528, 0x00378534, 0x00378538, 0x00378544, 0x00378548, 0x00180024, 0x00109B10, 0x001D5220, 0x00193840, 0x00050606}, 2931 | [BYOND_VERSION_ADJUSTED(1589)] = {0x00378524, 0x00378528, 0x00378534, 0x00378538, 0x00378544, 0x00378548, 0x00180024, 0x00109AA0, 0x001D5190, 0x00193710, 0x00050606}, 2932 | [BYOND_VERSION_ADJUSTED(1590)] = {0x00396974, 0x00396978, 0x00396984, 0x00396988, 0x00396994, 0x00396998, 0x00180024, 0x00118180, 0x001EA800, 0x001A6A80, 0x00050606}, 2933 | [BYOND_VERSION_ADJUSTED(1591)] = {0x00396974, 0x00396978, 0x00396984, 0x00396988, 0x00396994, 0x00396998, 0x00180024, 0x001175E0, 0x001E9F00, 0x001A5F00, 0x00050606}, 2934 | [BYOND_VERSION_ADJUSTED(1592)] = {0x00396974, 0x00396978, 0x00396984, 0x00396988, 0x00396994, 0x00396998, 0x00180024, 0x00117890, 0x001EA900, 0x001A6380, 0x00050606}, 2935 | [BYOND_VERSION_ADJUSTED(1593)] = {0x00396974, 0x00396978, 0x00396984, 0x00396988, 0x00396994, 0x00396998, 0x00180024, 0x00118090, 0x001EAB30, 0x001A6920, 0x00050606}, 2936 | [BYOND_VERSION_ADJUSTED(1594)] = {0x00397B6C, 0x00397B70, 0x00397B7C, 0x00397B80, 0x00397B8C, 0x00397B90, 0x00180024, 0x00118590, 0x001EBBB0, 0x001A8140, 0x00050606}, 2937 | [BYOND_VERSION_ADJUSTED(1595)] = {0x0039AB58, 0x0039AB5C, 0x0039AB68, 0x0039AB6C, 0x0039AB78, 0x0039AB7C, 0x00180024, 0x0011A810, 0x001EED90, 0x001AB310, 0x00050606}, 2938 | [BYOND_VERSION_ADJUSTED(1596)] = {0x0039AB58, 0x0039AB5C, 0x0039AB68, 0x0039AB6C, 0x0039AB78, 0x0039AB7C, 0x00180024, 0x0011A090, 0x001EE950, 0x001AAC20, 0x00050606}, 2939 | [BYOND_VERSION_ADJUSTED(1597)] = {0x0039CB74, 0x0039CB78, 0x0039CB84, 0x0039CB88, 0x0039CB94, 0x0039CB98, 0x00180024, 0x0011B5A0, 0x001EF8A0, 0x001AC2A0, 0x00050606}, 2940 | [BYOND_VERSION_ADJUSTED(1598)] = {0x0039EBC8, 0x0039EBCC, 0x0039EBD8, 0x0039EBDC, 0x0039EBE8, 0x0039EBEC, 0x00180024, 0x0011BF40, 0x001F0B40, 0x001ACFF0, 0x00050606}, 2941 | [BYOND_VERSION_ADJUSTED(1599)] = {0x0039EBC8, 0x0039EBCC, 0x0039EBD8, 0x0039EBDC, 0x0039EBE8, 0x0039EBEC, 0x00180024, 0x0011B640, 0x001F0910, 0x001AC9B0, 0x00050606}, 2942 | [BYOND_VERSION_ADJUSTED(1600)] = {0x0039EBC8, 0x0039EBCC, 0x0039EBD8, 0x0039EBDC, 0x0039EBE8, 0x0039EBEC, 0x00180024, 0x0011BE70, 0x001F08B0, 0x001AD170, 0x00050606}, 2943 | [BYOND_VERSION_ADJUSTED(1601)] = {0x0039FC0C, 0x0039FC10, 0x0039FC1C, 0x0039FC20, 0x0039FC2C, 0x0039FC30, 0x00180024, 0x0011BC70, 0x001F0DC0, 0x001ACAA0, 0x00050606}, 2944 | [BYOND_VERSION_ADJUSTED(1602)] = {0x003A2C50, 0x003A2C58, 0x003A2C68, 0x003A2C6C, 0x003A2C78, 0x003A2C7C, 0x00180024, 0x0011EB80, 0x001F3350, 0x001AF9F0, 0x00050606}, 2945 | [BYOND_VERSION_ADJUSTED(1603)] = {0x003A3DE0, 0x003A3DE8, 0x003A3DF8, 0x003A3DFC, 0x003A3E08, 0x003A3E0C, 0x00180024, 0x0011EC00, 0x001F3890, 0x001AFB90, 0x00050606}, 2946 | [BYOND_VERSION_ADJUSTED(1604)] = {0x003A1D88, 0x003A1D8C, 0x003A1D98, 0x003A1D9C, 0x003A1DA8, 0x003A1DAC, 0x00180024, 0x0011E570, 0x001F3A50, 0x001AF6D0, 0x00050606}, 2947 | [BYOND_VERSION_ADJUSTED(1605)] = {0x003A2D80, 0x003A2D84, 0x003A2D90, 0x003A2D94, 0x003A2DA0, 0x003A2DA4, 0x00180024, 0x0011E250, 0x001F3A20, 0x001AFAC0, 0x00050606}, 2948 | [BYOND_VERSION_ADJUSTED(1606)] = {0x003A2D80, 0x003A2D84, 0x003A2D90, 0x003A2D94, 0x003A2DA0, 0x003A2DA4, 0x00180024, 0x0011E230, 0x001F39C0, 0x001AFA50, 0x00050606}, 2949 | [BYOND_VERSION_ADJUSTED(1607)] = {0x003A3DE0, 0x003A3DE4, 0x003A3DF0, 0x003A3DF4, 0x003A3E00, 0x003A3E04, 0x00180024, 0x0011EF00, 0x001F48B0, 0x001B0560, 0x00050606}, 2950 | [BYOND_VERSION_ADJUSTED(1608)] = {0x003A3DE0, 0x003A3DE4, 0x003A3DF0, 0x003A3DF4, 0x003A3E00, 0x003A3E04, 0x00180024, 0x0011ED70, 0x001F4B30, 0x001B0680, 0x00050606}, 2951 | [BYOND_VERSION_ADJUSTED(1609)] = {0x003AB1E8, 0x003AB1EC, 0x003AB1F8, 0x003AB1FC, 0x003AB208, 0x003AB20C, 0x00180024, 0x0011FE90, 0x001F5900, 0x001B14D0, 0x00050606}, 2952 | [BYOND_VERSION_ADJUSTED(1610)] = {0x003AA23C, 0x003AA240, 0x003AA24C, 0x003AA250, 0x003AA25C, 0x003AA260, 0x00180024, 0x0011F670, 0x001F5C30, 0x001B1450, 0x00050606}, 2953 | [BYOND_VERSION_ADJUSTED(1611)] = {0x003AD3A8, 0x003AD3AC, 0x003AD3B8, 0x003AD3BC, 0x003AD3C8, 0x003AD3CC, 0x00180024, 0x0011F220, 0x001F5950, 0x001B0D10, 0x00050606}, 2954 | [BYOND_VERSION_ADJUSTED(1612)] = {0x003AD3A8, 0x003AD3AC, 0x003AD3B8, 0x003AD3BC, 0x003AD3C8, 0x003AD3CC, 0x00180024, 0x0011F220, 0x001F58F0, 0x001B0C90, 0x00050606}, 2955 | [BYOND_VERSION_ADJUSTED(1613)] = {0x003AD3A8, 0x003AD3AC, 0x003AD3B8, 0x003AD3BC, 0x003AD3C8, 0x003AD3CC, 0x00180024, 0x0011F3C0, 0x001F59E0, 0x001B0F20, 0x00050606}, 2956 | [BYOND_VERSION_ADJUSTED(1614)] = {0x003AC3A8, 0x003AC3AC, 0x003AC3B8, 0x003AC3BC, 0x003AC3C8, 0x003AC3CC, 0x00180024, 0x0011EBE0, 0x001F50E0, 0x001B0A50, 0x00050606}, 2957 | [BYOND_VERSION_ADJUSTED(1615)] = {0x004073E0, 0x004073E4, 0x004073F0, 0x004073F4, 0x00407400, 0x00407404, 0x00180024, 0x00130F20, 0x0020B580, 0x001C3AD0, 0x00050606}, 2958 | [BYOND_VERSION_ADJUSTED(1616)] = {0x004073E0, 0x004073E4, 0x004073F0, 0x004073F4, 0x00407400, 0x00407404, 0x00180024, 0x00131210, 0x0020B9E0, 0x001C3E20, 0x00050606}, 2959 | [BYOND_VERSION_ADJUSTED(1617)] = {0x004074B0, 0x004074B4, 0x004074C0, 0x004074C4, 0x004074D0, 0x004074D4, 0x00180028, 0x001312D0, 0x0020BAB0, 0x001C3EB0, 0x00050606}, 2960 | [BYOND_VERSION_ADJUSTED(1618)] = {0x004074B0, 0x004074B4, 0x004074C0, 0x004074C4, 0x004074D0, 0x004074D4, 0x00180028, 0x00131350, 0x0020BBA0, 0x001C3F40, 0x00050606}, 2961 | [BYOND_VERSION_ADJUSTED(1619)] = {0x004074B0, 0x004074B4, 0x004074C0, 0x004074C4, 0x004074D0, 0x004074D4, 0x00180028, 0x00131350, 0x0020BBA0, 0x001C3F40, 0x00050606}, 2962 | [BYOND_VERSION_ADJUSTED(1620)] = {0x0040758C, 0x00407590, 0x0040759C, 0x004075A0, 0x004075AC, 0x004075B0, 0x00180028, 0x001313C0, 0x0020BC00, 0x001C3F60, 0x00050606}, 2963 | [BYOND_VERSION_ADJUSTED(1621)] = {0x0040758C, 0x00407590, 0x0040759C, 0x004075A0, 0x004075AC, 0x004075B0, 0x00180028, 0x001313B0, 0x0020BC70, 0x001C3FC0, 0x00050606}, 2964 | [BYOND_VERSION_ADJUSTED(1622)] = {0x0040755C, 0x00407560, 0x0040756C, 0x00407570, 0x0040757C, 0x00407580, 0x00180028, 0x001312D0, 0x0020BB90, 0x001C3EB0, 0x00050606}, 2965 | [BYOND_VERSION_ADJUSTED(1623)] = {0x0040755C, 0x00407560, 0x0040756C, 0x00407570, 0x0040757C, 0x00407580, 0x00180028, 0x001312D0, 0x0020BB90, 0x001C3EB0, 0x00050606}, 2966 | [BYOND_VERSION_ADJUSTED(1624)] = {0x00407564, 0x00407568, 0x00407574, 0x00407578, 0x00407584, 0x00407588, 0x001C002C, 0x00130D40, 0x0020B810, 0x001C3940, 0x00050606}, 2967 | [BYOND_VERSION_ADJUSTED(1625)] = {0x00407564, 0x00407568, 0x00407574, 0x00407578, 0x00407584, 0x00407588, 0x001C002C, 0x00130D40, 0x0020B810, 0x001C3940, 0x00050606}, 2968 | [BYOND_VERSION_ADJUSTED(1626)] = {0x00407564, 0x00407568, 0x00407574, 0x00407578, 0x00407584, 0x00407588, 0x001C002C, 0x00130CF0, 0x0020B780, 0x001C38C0, 0x00050606}, 2969 | [BYOND_VERSION_ADJUSTED(1627)] = {0x0040556C, 0x00405570, 0x0040557C, 0x00405580, 0x0040558C, 0x00405590, 0x001C002C, 0x0012F570, 0x0020A030, 0x001C2140, 0x00050606}, 2970 | [BYOND_VERSION_ADJUSTED(1630)] = {0x0040556C, 0x00405570, 0x0040557C, 0x00405580, 0x0040558C, 0x00405590, 0x001C002C, 0x0012F710, 0x0020A2E0, 0x001C2430, 0x00050606}, 2971 | [BYOND_VERSION_ADJUSTED(1631)] = {0x0040756C, 0x00407570, 0x0040757C, 0x00407580, 0x0040758C, 0x00407590, 0x001C002C, 0x0012FB30, 0x0020A830, 0x001C2970, 0x00050606}, 2972 | [BYOND_VERSION_ADJUSTED(1632)] = {0x0040756C, 0x00407570, 0x0040757C, 0x00407580, 0x0040758C, 0x00407590, 0x001C002C, 0x0012FC00, 0x0020A8D0, 0x001C29D0, 0x00050606}, 2973 | [BYOND_VERSION_ADJUSTED(1633)] = {0x00407574, 0x00407578, 0x00407584, 0x00407588, 0x00407594, 0x00407598, 0x001C002C, 0x0012FCF0, 0x0020A9D0, 0x001C2AE0, 0x00050606}, 2974 | [BYOND_VERSION_ADJUSTED(1634)] = {0x00408574, 0x00408578, 0x00408584, 0x00408588, 0x00408594, 0x00408598, 0x001C002C, 0x0012FCF0, 0x0020A9D0, 0x001C2AE0, 0x00050606}, 2975 | [BYOND_VERSION_ADJUSTED(1635)] = {0x00408574, 0x00408578, 0x00408584, 0x00408588, 0x00408594, 0x00408598, 0x001C002C, 0x0012FE00, 0x0020AAD0, 0x001C2BD0, 0x00050606}, 2976 | [BYOND_VERSION_ADJUSTED(1636)] = {0x0040860C, 0x00408610, 0x0040861C, 0x00408620, 0x0040862C, 0x00408630, 0x001C002C, 0x0012FFE0, 0x0020AEE0, 0x001C2F60, 0x00050606}, 2977 | [BYOND_VERSION_ADJUSTED(1637)] = {0x0040860C, 0x00408610, 0x0040861C, 0x00408620, 0x0040862C, 0x00408630, 0x001C002C, 0x00130290, 0x0020B290, 0x001C3270, 0x00050606}, 2978 | [BYOND_VERSION_ADJUSTED(1638)] = {0x0040960C, 0x00409610, 0x0040961C, 0x00409620, 0x0040962C, 0x00409630, 0x001C002C, 0x00130AE0, 0x0020BB10, 0x001C3AE0, 0x00050606}, 2979 | [BYOND_VERSION_ADJUSTED(1639)] = {0x0040960C, 0x00409610, 0x0040961C, 0x00409620, 0x0040962C, 0x00409630, 0x001C002C, 0x00130AE0, 0x0020BB10, 0x001C3AE0, 0x00050606}, 2980 | [BYOND_VERSION_ADJUSTED(1640)] = {0x0040960C, 0x00409610, 0x0040961C, 0x00409620, 0x0040962C, 0x00409630, 0x001C002C, 0x00130AA0, 0x0020BB40, 0x001C3AE0, 0x00050606}, 2981 | [BYOND_VERSION_ADJUSTED(1641)] = {0x00409614, 0x00409618, 0x00409624, 0x00409628, 0x00409634, 0x00409638, 0x001C002C, 0x00130B20, 0x0020BA10, 0x001C3890, 0x00050606}, 2982 | [BYOND_VERSION_ADJUSTED(1642)] = {0x00409614, 0x00409618, 0x00409624, 0x00409628, 0x00409634, 0x00409638, 0x001C002C, 0x00130B20, 0x0020BAE0, 0x001C3940, 0x00050606}, 2983 | [BYOND_VERSION_ADJUSTED(1643)] = {0x0040961C, 0x00409620, 0x0040962C, 0x00409630, 0x0040963C, 0x00409640, 0x001C002C, 0x00130B20, 0x0020BAD0, 0x001C38E0, 0x00050606}, 2984 | [BYOND_VERSION_ADJUSTED(1644)] = {0x004096BC, 0x004096C0, 0x004096CC, 0x004096D0, 0x004096DC, 0x004096E0, 0x001C002C, 0x00130D60, 0x0020BD20, 0x001C3B90, 0x00050606}, 2985 | [BYOND_VERSION_ADJUSTED(1645)] = {0x0040A6C4, 0x0040A6C8, 0x0040A6D4, 0x0040A6D8, 0x0040A6E4, 0x0040A6E8, 0x001C002C, 0x00131240, 0x0020C260, 0x001C4060, 0x00050606}, 2986 | [BYOND_VERSION_ADJUSTED(1646)] = {0x0040A6C4, 0x0040A6C8, 0x0040A6D4, 0x0040A6D8, 0x0040A6E4, 0x0040A6E8, 0x001C002C, 0x00131310, 0x0020C300, 0x001C4160, 0x00050606}, 2987 | [BYOND_VERSION_ADJUSTED(1647)] = {0x0040A6C4, 0x0040A6C8, 0x0040A6D4, 0x0040A6D8, 0x0040A6E4, 0x0040A6E8, 0x001C002C, 0x00131260, 0x0020c430, 0x001C4250, 0x00050606}, 2988 | }; 2989 | 2990 | #elif defined(UTRACY_LINUX) 2991 | # define BYOND_MAX_BUILD 1647 2992 | # define BYOND_MIN_BUILD 1543 2993 | # define BYOND_VERSION_ADJUSTED(a) ((a) - BYOND_MIN_BUILD) 2994 | 2995 | static int unsigned const byond_offsets[][11] = { 2996 | /* strings strings_len miscs miscs_len procdefs procdefs_len procdef exec_proc server_tick send_maps prologue */ 2997 | [BYOND_VERSION_ADJUSTED(1543)] = {0x0063F9B8, 0x0063F9BC, 0x0063F9D0, 0x0063F9D4, 0x0063FA0C, 0x0063FA10, 0x00180024, 0x002E31E0, 0x002B7710, 0x002B28D0, 0x00050505}, 2998 | [BYOND_VERSION_ADJUSTED(1544)] = {0x00640BB8, 0x00640BBC, 0x00640BD0, 0x00640BD4, 0x00640C0C, 0x00640C10, 0x00180024, 0x002E3A60, 0x002B7F90, 0x002B3150, 0x00050505}, 2999 | [BYOND_VERSION_ADJUSTED(1545)] = {0x006409D8, 0x006409DC, 0x006409F0, 0x006409F4, 0x00640A2C, 0x00640A30, 0x00180024, 0x002E3D00, 0x002B8230, 0x002B33F0, 0x00050505}, 3000 | [BYOND_VERSION_ADJUSTED(1546)] = {0x006409D8, 0x006409DC, 0x006409F0, 0x006409F4, 0x00640A2C, 0x00640A30, 0x00180024, 0x002E3ED0, 0x002B83F0, 0x002B3570, 0x00050505}, 3001 | [BYOND_VERSION_ADJUSTED(1547)] = {0x00642A38, 0x00642A3C, 0x00642A50, 0x00642A54, 0x00642A8C, 0x00642A90, 0x00180024, 0x002E4D30, 0x002B8F40, 0x002B4320, 0x00050505}, 3002 | [BYOND_VERSION_ADJUSTED(1548)] = {0x00643A38, 0x00643A3C, 0x00643A50, 0x00643A54, 0x00643A8C, 0x00643A90, 0x00180024, 0x002E5CB0, 0x002B9ED0, 0x002B52B0, 0x00050505}, 3003 | [BYOND_VERSION_ADJUSTED(1549)] = {0x006459D8, 0x006459DC, 0x006459F0, 0x006459F4, 0x00645A2C, 0x00645A30, 0x00180024, 0x002E6C30, 0x002BADD0, 0x002B5F10, 0x00050505}, 3004 | [BYOND_VERSION_ADJUSTED(1550)] = {0x006469D8, 0x006469DC, 0x006469F0, 0x006469F4, 0x00646A2C, 0x00646A30, 0x00180024, 0x002E7B80, 0x002BB910, 0x002B6A50, 0x00050505}, 3005 | [BYOND_VERSION_ADJUSTED(1551)] = {0x006469D8, 0x006469DC, 0x006469F0, 0x006469F4, 0x00646A2C, 0x00646A30, 0x00180024, 0x002E77C0, 0x002BB520, 0x002B6660, 0x00050505}, 3006 | [BYOND_VERSION_ADJUSTED(1552)] = {0x006469D8, 0x006469DC, 0x006469F0, 0x006469F4, 0x00646A2C, 0x00646A30, 0x00180024, 0x002E7D20, 0x002BBA70, 0x002B6BB0, 0x00050505}, 3007 | [BYOND_VERSION_ADJUSTED(1553)] = {0x00651B18, 0x00651B1C, 0x00651B30, 0x00651B34, 0x00651B6C, 0x00651B70, 0x00180024, 0x002F1490, 0x002C51E0, 0x002BCE30, 0x00050505}, 3008 | [BYOND_VERSION_ADJUSTED(1554)] = {0x00651B18, 0x00651B1C, 0x00651B30, 0x00651B34, 0x00651B6C, 0x00651B70, 0x00180024, 0x002F1D10, 0x002C5280, 0x002BCED0, 0x00050505}, 3009 | [BYOND_VERSION_ADJUSTED(1555)] = {0x00653B28, 0x00653B2C, 0x00653B40, 0x00653B44, 0x00653B8C, 0x00653B90, 0x00180024, 0x002F2EA0, 0x002C5F90, 0x002BE1A0, 0x00050505}, 3010 | [BYOND_VERSION_ADJUSTED(1556)] = {0x00653B28, 0x00653B2C, 0x00653B40, 0x00653B44, 0x00653B8C, 0x00653B90, 0x00180024, 0x002F2BE0, 0x002C5CD0, 0x002BDEE0, 0x00050505}, 3011 | [BYOND_VERSION_ADJUSTED(1557)] = {0x00653B28, 0x00653B2C, 0x00653B40, 0x00653B44, 0x00653B8C, 0x00653B90, 0x00180024, 0x002F2A40, 0x002C5B40, 0x002BDD50, 0x00050505}, 3012 | [BYOND_VERSION_ADJUSTED(1558)] = {0x00656B48, 0x00656B4C, 0x00656B60, 0x00656B64, 0x00656BAC, 0x00656BB0, 0x00180024, 0x002F5020, 0x002C8070, 0x002C0280, 0x00050505}, 3013 | [BYOND_VERSION_ADJUSTED(1559)] = {0x00656B48, 0x00656B4C, 0x00656B60, 0x00656B64, 0x00656BAC, 0x00656BB0, 0x00180024, 0x002F5020, 0x002C8070, 0x002C0280, 0x00050505}, 3014 | [BYOND_VERSION_ADJUSTED(1560)] = {0x00656B48, 0x00656B4C, 0x00656B60, 0x00656B64, 0x00656BAC, 0x00656BB0, 0x00180024, 0x002F5040, 0x002C8090, 0x002C02A0, 0x00050505}, 3015 | [BYOND_VERSION_ADJUSTED(1562)] = {0x0065AB48, 0x0065AB4C, 0x0065AB60, 0x0065AB64, 0x0065ABAC, 0x0065ABB0, 0x00180024, 0x002F89B0, 0x002CBA20, 0x002C3C30, 0x00050505}, 3016 | [BYOND_VERSION_ADJUSTED(1563)] = {0x0065ABC8, 0x0065ABCC, 0x0065ABE0, 0x0065ABE4, 0x0065AC2C, 0x0065AC30, 0x00180024, 0x002F87E0, 0x002CB850, 0x002C3A60, 0x00050505}, 3017 | [BYOND_VERSION_ADJUSTED(1564)] = {0x00659B48, 0x00659B4C, 0x00659B60, 0x00659B64, 0x00659BAC, 0x00659BB0, 0x00180024, 0x002F8680, 0x002CB6F0, 0x002C3900, 0x00050505}, 3018 | [BYOND_VERSION_ADJUSTED(1565)] = {0x0065FB48, 0x0065FB4C, 0x0065FB60, 0x0065FB64, 0x0065FBAC, 0x0065FBB0, 0x00180024, 0x002F9990, 0x002CCA00, 0x002C4C10, 0x00050505}, 3019 | [BYOND_VERSION_ADJUSTED(1566)] = {0x0065EB48, 0x0065EB4C, 0x0065EB60, 0x0065EB64, 0x0065EBAC, 0x0065EBB0, 0x00180024, 0x002F8830, 0x002CB8A0, 0x002C3AB0, 0x00050505}, 3020 | [BYOND_VERSION_ADJUSTED(1567)] = {0x0065CB48, 0x0065CB4C, 0x0065CB60, 0x0065CB64, 0x0065CBAC, 0x0065CBB0, 0x00180024, 0x002F74D0, 0x002CA480, 0x002C2690, 0x00050505}, 3021 | [BYOND_VERSION_ADJUSTED(1568)] = {0x0065CB48, 0x0065CB4C, 0x0065CB60, 0x0065CB64, 0x0065CBAC, 0x0065CBB0, 0x00180024, 0x002F74D0, 0x002CA480, 0x002C2690, 0x00050505}, 3022 | [BYOND_VERSION_ADJUSTED(1569)] = {0x0065CB48, 0x0065CB4C, 0x0065CB60, 0x0065CB64, 0x0065CBAC, 0x0065CBB0, 0x00180024, 0x002F74C0, 0x002CA470, 0x002C2680, 0x00050505}, 3023 | [BYOND_VERSION_ADJUSTED(1570)] = {0x0065CB48, 0x0065CB4C, 0x0065CB60, 0x0065CB64, 0x0065CBAC, 0x0065CBB0, 0x00180024, 0x002F78E0, 0x002CA870, 0x002C2A90, 0x00050505}, 3024 | [BYOND_VERSION_ADJUSTED(1571)] = {0x0065CB48, 0x0065CB4C, 0x0065CB60, 0x0065CB64, 0x0065CBAC, 0x0065CBB0, 0x00180024, 0x002F7900, 0x002CA890, 0x002C2AB0, 0x00050505}, 3025 | [BYOND_VERSION_ADJUSTED(1572)] = {0x0065DB48, 0x0065DB4C, 0x0065DB60, 0x0065DB64, 0x0065DBAC, 0x0065DBB0, 0x00180024, 0x002F8110, 0x002CB0A0, 0x002C32C0, 0x00050505}, 3026 | [BYOND_VERSION_ADJUSTED(1573)] = {0x0065DC28, 0x0065DC2C, 0x0065DC40, 0x0065DC44, 0x0065DC8C, 0x0065DC90, 0x00180024, 0x002F7EE0, 0x002CAE70, 0x002C3090, 0x00050505}, 3027 | [BYOND_VERSION_ADJUSTED(1574)] = {0x0065DB68, 0x0065DB6C, 0x0065DB80, 0x0065DB84, 0x0065DBCC, 0x0065DBD0, 0x00180024, 0x002F8280, 0x002CB210, 0x002C3430, 0x00050505}, 3028 | [BYOND_VERSION_ADJUSTED(1575)] = {0x0065DB68, 0x0065DB6C, 0x0065DB80, 0x0065DB84, 0x0065DBCC, 0x0065DBD0, 0x00180024, 0x002F8280, 0x002CB210, 0x002C3430, 0x00050505}, 3029 | [BYOND_VERSION_ADJUSTED(1576)] = {0x00664BC8, 0x00664BCC, 0x00664BE0, 0x00664BE4, 0x00664C2C, 0x00664C30, 0x00180024, 0x002FCFC0, 0x002CFF50, 0x002C8170, 0x00050505}, 3030 | [BYOND_VERSION_ADJUSTED(1577)] = {0x00664BC8, 0x00664BCC, 0x00664BE0, 0x00664BE4, 0x00664C2C, 0x00664C30, 0x00180024, 0x002FCFD0, 0x002CFF60, 0x002C8180, 0x00050505}, 3031 | [BYOND_VERSION_ADJUSTED(1578)] = {0x00664D08, 0x00664D0C, 0x00664D20, 0x00664D24, 0x00664D6C, 0x00664D70, 0x00180024, 0x002FC5D0, 0x002CF550, 0x002C7770, 0x00050505}, 3032 | [BYOND_VERSION_ADJUSTED(1579)] = {0x00664BCC, 0x00664BD0, 0x00664BE4, 0x00664BE8, 0x00664C2C, 0x00664C30, 0x00180024, 0x002FC740, 0x002CF590, 0x002C77B0, 0x00050505}, 3033 | [BYOND_VERSION_ADJUSTED(1580)] = {0x00664BCC, 0x00664BD0, 0x00664BE4, 0x00664BE8, 0x00664C2C, 0x00664C30, 0x00180024, 0x002FC760, 0x002CF5A0, 0x002C77C0, 0x00050505}, 3034 | [BYOND_VERSION_ADJUSTED(1581)] = {0x00664BCC, 0x00664BD0, 0x00664BE4, 0x00664BE8, 0x00664C2C, 0x00664C30, 0x00180024, 0x002FC740, 0x002CF580, 0x002C77A0, 0x00050505}, 3035 | [BYOND_VERSION_ADJUSTED(1582)] = {0x00666C2C, 0x00666C30, 0x00666C44, 0x00666C48, 0x00666C8C, 0x00666C90, 0x00180024, 0x002FCEF0, 0x002CFBE0, 0x002C7E00, 0x00050505}, 3036 | [BYOND_VERSION_ADJUSTED(1583)] = {0x00666BCC, 0x00666BD0, 0x00666BE4, 0x00666BE8, 0x00666C2C, 0x00666C30, 0x00180024, 0x002FCEF0, 0x002CFBE0, 0x002C7E00, 0x00050505}, 3037 | [BYOND_VERSION_ADJUSTED(1584)] = {0x00668BCC, 0x00668BD0, 0x00668BE4, 0x00668BE8, 0x00668C2C, 0x00668C30, 0x00180024, 0x002FD510, 0x002D0200, 0x002C85D0, 0x00050505}, 3038 | [BYOND_VERSION_ADJUSTED(1585)] = {0x0066BBEC, 0x0066BBF0, 0x0066BC04, 0x0066BC08, 0x0066BC4C, 0x0066BC50, 0x00180024, 0x00300350, 0x002D2E90, 0x002CB2B0, 0x00050505}, 3039 | [BYOND_VERSION_ADJUSTED(1586)] = {0x0066FC0C, 0x0066FC10, 0x0066FC24, 0x0066FC28, 0x0066FC6C, 0x0066FC70, 0x00180024, 0x00303C40, 0x002D6770, 0x002CE3D0, 0x00050505}, 3040 | [BYOND_VERSION_ADJUSTED(1587)] = {0x0066FC0C, 0x0066FC10, 0x0066FC24, 0x0066FC28, 0x0066FC6C, 0x0066FC70, 0x00180024, 0x00303CF0, 0x002D6820, 0x002CE480, 0x00050505}, 3041 | [BYOND_VERSION_ADJUSTED(1588)] = {0x0066FC0C, 0x0066FC10, 0x0066FC24, 0x0066FC28, 0x0066FC6C, 0x0066FC70, 0x00180024, 0x00303CC0, 0x002D67F0, 0x002CE450, 0x00050505}, 3042 | [BYOND_VERSION_ADJUSTED(1589)] = {0x00671C0C, 0x00671C10, 0x00671C24, 0x00671C28, 0x00671C6C, 0x00671C70, 0x00180024, 0x00305550, 0x002D80A0, 0x002CFD50, 0x00050505}, 3043 | [BYOND_VERSION_ADJUSTED(1590)] = {0x006B15E8, 0x006B15EC, 0x006B1600, 0x006B1604, 0x006B164C, 0x006B1650, 0x00180024, 0x00313220, 0x002FFBA0, 0x002F5DA0, 0x00050505}, 3044 | [BYOND_VERSION_ADJUSTED(1591)] = {0x006B17C8, 0x006B17CC, 0x006B17E0, 0x006B17E4, 0x006B182C, 0x006B1830, 0x00180024, 0x00313440, 0x002FFDC0, 0x002F5DC0, 0x00050505}, 3045 | [BYOND_VERSION_ADJUSTED(1592)] = {0x006B19C8, 0x006B19CC, 0x006B19E0, 0x006B19E4, 0x006B1A2C, 0x006B1A30, 0x00180024, 0x003135F0, 0x002FFF70, 0x002F5F70, 0x00050505}, 3046 | [BYOND_VERSION_ADJUSTED(1593)] = {0x006B1C68, 0x006B1C6C, 0x006B1C80, 0x006B1C84, 0x006B1CCC, 0x006B1CD0, 0x00180024, 0x00313820, 0x003001A0, 0x002F61A0, 0x00050505}, 3047 | [BYOND_VERSION_ADJUSTED(1594)] = {0x006B7C68, 0x006B7C6C, 0x006B7C80, 0x006B7C84, 0x006B7CCC, 0x006B7CD0, 0x00180024, 0x003172C0, 0x00303B80, 0x002F9C40, 0x00050505}, 3048 | [BYOND_VERSION_ADJUSTED(1595)] = {0x006BA7A8, 0x006BA7AC, 0x006BA7C0, 0x006BA7C4, 0x006BA80C, 0x006BA810, 0x00180024, 0x003163B0, 0x00303400, 0x002F94C0, 0x00050505}, 3049 | [BYOND_VERSION_ADJUSTED(1596)] = {0x006BB348, 0x006BB34C, 0x006BB360, 0x006BB364, 0x006BB3AC, 0x006BB3B0, 0x00180024, 0x00316D60, 0x00303F80, 0x002FA040, 0x00050505}, 3050 | [BYOND_VERSION_ADJUSTED(1597)] = {0x006BC068, 0x006BC06C, 0x006BC080, 0x006BC084, 0x006BC0CC, 0x006BC0D0, 0x00180024, 0x003188A0, 0x00305AC0, 0x002FBB80, 0x00050505}, 3051 | [BYOND_VERSION_ADJUSTED(1598)] = {0x006C4288, 0x006C428C, 0x006C42A0, 0x006C42A4, 0x006C42EC, 0x006C42F0, 0x00180024, 0x0031B540, 0x003077D0, 0x002FD810, 0x00050505}, 3052 | [BYOND_VERSION_ADJUSTED(1599)] = {0x006C3AE8, 0x006C3AEC, 0x006C3B00, 0x006C3B04, 0x006C3B4C, 0x006C3B50, 0x00180024, 0x0031B0A0, 0x00307330, 0x002FD370, 0x00050505}, 3053 | [BYOND_VERSION_ADJUSTED(1600)] = {0x006C38A8, 0x006C38AC, 0x006C38C0, 0x006C38C4, 0x006C390C, 0x006C3910, 0x00180024, 0x0031AE30, 0x003070C0, 0x002FD100, 0x00050505}, 3054 | [BYOND_VERSION_ADJUSTED(1601)] = {0x006C5B48, 0x006C5B4C, 0x006C5B60, 0x006C5B64, 0x006C5BAC, 0x006C5BB0, 0x00180024, 0x0031B790, 0x00307A80, 0x002FD9A0, 0x00050505}, 3055 | [BYOND_VERSION_ADJUSTED(1602)] = {0x006CD928, 0x006CD92C, 0x006CD940, 0x006CD944, 0x006CD98C, 0x006CD990, 0x00180024, 0x00322000, 0x0030E300, 0x003041E0, 0x00050505}, 3056 | [BYOND_VERSION_ADJUSTED(1603)] = {0x006CF7A8, 0x006CF7AC, 0x006CF7C0, 0x006CF7C4, 0x006CF80C, 0x006CF810, 0x00180024, 0x00321F50, 0x0030E260, 0x003042A0, 0x00050505}, 3057 | [BYOND_VERSION_ADJUSTED(1604)] = {0x006CD4E8, 0x006CD4EC, 0x006CD500, 0x006CD504, 0x006CD54C, 0x006CD550, 0x00180024, 0x00321CC0, 0x0030DF60, 0x00304550, 0x00050505}, 3058 | [BYOND_VERSION_ADJUSTED(1605)] = {0x006CD868, 0x006CD86C, 0x006CD880, 0x006CD884, 0x006CD8CC, 0x006CD8D0, 0x00180024, 0x00321F10, 0x0030E130, 0x00306750, 0x00050505}, 3059 | [BYOND_VERSION_ADJUSTED(1606)] = {0x006CD8C8, 0x006CD8CC, 0x006CD8E0, 0x006CD8E4, 0x006CD92C, 0x006CD930, 0x00180024, 0x00321F30, 0x0030E150, 0x00306770, 0x00050505}, 3060 | [BYOND_VERSION_ADJUSTED(1607)] = {0x006CA928, 0x006CA92C, 0x006CA940, 0x006CA944, 0x006CA98C, 0x006CA990, 0x00180024, 0x0031F170, 0x0030B370, 0x00303970, 0x00050505}, 3061 | [BYOND_VERSION_ADJUSTED(1608)] = {0x006CA628, 0x006CA62C, 0x006CA640, 0x006CA644, 0x006CA68C, 0x006CA690, 0x00180024, 0x0031EF70, 0x0030B170, 0x00303770, 0x00050505}, 3062 | [BYOND_VERSION_ADJUSTED(1609)] = {0x006DFB88, 0x006DFB8C, 0x006DFBA0, 0x006DFBA4, 0x006DFBEC, 0x006DFBF0, 0x00180024, 0x00326A20, 0x00312B20, 0x0030A810, 0x00050505}, 3063 | [BYOND_VERSION_ADJUSTED(1610)] = {0x006DE428, 0x006DE42C, 0x006DE440, 0x006DE444, 0x006DE48C, 0x006DE490, 0x00180024, 0x00325850, 0x00311790, 0x003093D0, 0x00050505}, 3064 | [BYOND_VERSION_ADJUSTED(1611)] = {0x006D69E8, 0x006D69EC, 0x006D6A00, 0x006D6A04, 0x006D6A4C, 0x006D6A50, 0x00180024, 0x00322AA0, 0x0030FA20, 0x00307660, 0x00050505}, 3065 | [BYOND_VERSION_ADJUSTED(1613)] = {0x006D6C48, 0x006D6C4C, 0x006D6C60, 0x006D6C64, 0x006D6CAC, 0x006D6CB0, 0x00180024, 0x00322CD0, 0x0030FC50, 0x00307890, 0x00050505}, 3066 | [BYOND_VERSION_ADJUSTED(1614)] = {0x006D62C8, 0x006D62CC, 0x006D62E0, 0x006D62E4, 0x006D632C, 0x006D6330, 0x00180024, 0x00323550, 0x003104B0, 0x003080F0, 0x00050505}, 3067 | [BYOND_VERSION_ADJUSTED(1615)] = {0x006D83E8, 0x006D83EC, 0x006D8400, 0x006D8404, 0x006D844C, 0x006D8450, 0x00180024, 0x00324FF0, 0x00311F50, 0x00309B90, 0x00050505}, 3068 | [BYOND_VERSION_ADJUSTED(1616)] = {0x006D8608, 0x006D860C, 0x006D8620, 0x006D8624, 0x006D866C, 0x006D8670, 0x00180024, 0x00325190, 0x003120F0, 0x00309D30, 0x00050505}, 3069 | [BYOND_VERSION_ADJUSTED(1617)] = {0x006DA978, 0x006DA97C, 0x006DA990, 0x006DA994, 0x006DA9CC, 0x006DA9D0, 0x00180028, 0x00326510, 0x00313430, 0x0030B070, 0x00050505}, 3070 | [BYOND_VERSION_ADJUSTED(1618)] = {0x006DA6D8, 0x006DA6DC, 0x006DA6F0, 0x006DA6F4, 0x006DA72C, 0x006DA730, 0x00180028, 0x00326250, 0x00313170, 0x0030ADB0, 0x00050505}, 3071 | [BYOND_VERSION_ADJUSTED(1619)] = {0x006DA698, 0x006DA69C, 0x006DA6B0, 0x006DA6B4, 0x006DA6EC, 0x006DA6F0, 0x00180028, 0x00326240, 0x00313160, 0x0030ADA0, 0x00050505}, 3072 | [BYOND_VERSION_ADJUSTED(1620)] = {0x006D61D8, 0x006D61DC, 0x006D61F0, 0x006D61F4, 0x006D622C, 0x006D6230, 0x00180028, 0x00324BE0, 0x00311AE0, 0x00309720, 0x00050505}, 3073 | [BYOND_VERSION_ADJUSTED(1621)] = {0x006D8698, 0x006D869C, 0x006D86B0, 0x006D86B4, 0x006D86EC, 0x006D86F0, 0x00180028, 0x003252F0, 0x003121F0, 0x00309E30, 0x00050505}, 3074 | [BYOND_VERSION_ADJUSTED(1622)] = {0x006D71B8, 0x006D71BC, 0x006D71D0, 0x006D71D4, 0x006D720C, 0x006D7210, 0x00180028, 0x00324BC0, 0x00311AC0, 0x00309700, 0x00050505}, 3075 | [BYOND_VERSION_ADJUSTED(1623)] = {0x006D71B8, 0x006D71BC, 0x006D71D0, 0x006D71D4, 0x006D720C, 0x006D7210, 0x00180028, 0x00324BD0, 0x00311AD0, 0x00309710, 0x00050505}, 3076 | [BYOND_VERSION_ADJUSTED(1624)] = {0x006D6198, 0x006D619C, 0x006D61B0, 0x006D61B4, 0x006D61EC, 0x006D61F0, 0x001C002C, 0x00323E00, 0x00310C60, 0x003088A0, 0x00050505}, 3077 | [BYOND_VERSION_ADJUSTED(1625)] = {0x006D6198, 0x006D619C, 0x006D61B0, 0x006D61B4, 0x006D61EC, 0x006D61F0, 0x001C002C, 0x00323E20, 0x00310C80, 0x003088C0, 0x00050505}, 3078 | [BYOND_VERSION_ADJUSTED(1626)] = {0x006D6198, 0x006D619C, 0x006D61B0, 0x006D61B4, 0x006D61EC, 0x006D61F0, 0x001C002C, 0x00323BC0, 0x00310A20, 0x00308660, 0x00050505}, 3079 | [BYOND_VERSION_ADJUSTED(1627)] = {0x006D3198, 0x006D319C, 0x006D31B0, 0x006D31B4, 0x006D31EC, 0x006D31F0, 0x001C002C, 0x00320D10, 0x0030DB70, 0x003057B0, 0x00050505}, 3080 | [BYOND_VERSION_ADJUSTED(1630)] = {0x006D47B8, 0x006D47BC, 0x006D47D0, 0x006D47D4, 0x006D480C, 0x006D4810, 0x001C002C, 0x003213E0, 0x0030E240, 0x00305E80, 0x00050505}, 3081 | [BYOND_VERSION_ADJUSTED(1631)] = {0x006D84D8, 0x006D84DC, 0x006D84F0, 0x006D84F4, 0x006D852C, 0x006D8530, 0x001C002C, 0x00322120, 0x0030EF80, 0x00306BC0, 0x00050505}, 3082 | [BYOND_VERSION_ADJUSTED(1632)] = {0x006D85F8, 0x006D85FC, 0x006D8610, 0x006D8614, 0x006D864C, 0x006D8650, 0x001C002C, 0x00322140, 0x0030EFA0, 0x00306BE0, 0x00050505}, 3083 | [BYOND_VERSION_ADJUSTED(1633)] = {0x006D8778, 0x006D877C, 0x006D8790, 0x006D8794, 0x006D87CC, 0x006D87D0, 0x001C002C, 0x003220D0, 0x0030EF30, 0x00306B70, 0x00050505}, 3084 | [BYOND_VERSION_ADJUSTED(1634)] = {0x006D8798, 0x006D879C, 0x006D87B0, 0x006D87B4, 0x006D87EC, 0x006D87F0, 0x001C002C, 0x00322150, 0x0030EFB0, 0x00306BF0, 0x00050505}, 3085 | [BYOND_VERSION_ADJUSTED(1635)] = {0x006D8798, 0x006D879C, 0x006D87B0, 0x006D87B4, 0x006D87EC, 0x006D87F0, 0x001C002C, 0x003220E0, 0x0030EF40, 0x00306B80, 0x00050505}, 3086 | [BYOND_VERSION_ADJUSTED(1636)] = {0x006D9198, 0x006D919C, 0x006D91B0, 0x006D91B4, 0x006D91EC, 0x006D91F0, 0x001C002C, 0x00322D40, 0x0030FBA0, 0x003065A0, 0x00050505}, 3087 | [BYOND_VERSION_ADJUSTED(1637)] = {0x006DA338, 0x006DA33C, 0x006DA350, 0x006DA354, 0x006DA38C, 0x006DA390, 0x001C002C, 0x003228B0, 0x0030FEF0, 0x003068F0, 0x00050505}, 3088 | [BYOND_VERSION_ADJUSTED(1638)] = {0x006DAC58, 0x006DAC5C, 0x006DAC70, 0x006DAC74, 0x006DACAC, 0x006DACB0, 0x001C002C, 0x00322E00, 0x00310440, 0x00306E40, 0x00050505}, 3089 | [BYOND_VERSION_ADJUSTED(1639)] = {0x006DA198, 0x006DA19C, 0x006DA1B0, 0x006DA1B4, 0x006DA1EC, 0x006DA1F0, 0x001C002C, 0x00322F10, 0x00310550, 0x00306F50, 0x00050505}, 3090 | [BYOND_VERSION_ADJUSTED(1640)] = {0x006DB498, 0x006DB49C, 0x006DB4B0, 0x006DB4B4, 0x006DB4EC, 0x006DB4F0, 0x001C002C, 0x00323160, 0x003107B0, 0x003071B0, 0x00050505}, 3091 | [BYOND_VERSION_ADJUSTED(1641)] = {0x006DB678, 0x006DB67C, 0x006DB690, 0x006DB694, 0x006DB6CC, 0x006DB6D0, 0x001C002C, 0x00322FD0, 0x00310590, 0x00306F90, 0x00050505}, 3092 | [BYOND_VERSION_ADJUSTED(1642)] = {0x006DB818, 0x006DB81C, 0x006DB830, 0x006DB834, 0x006DB86C, 0x006DB870, 0x001C002C, 0x00323000, 0x003105C0, 0x00306FC0, 0x00050505}, 3093 | [BYOND_VERSION_ADJUSTED(1643)] = {0x006DB618, 0x006DB61C, 0x006DB630, 0x006DB634, 0x006DB66C, 0x006DB670, 0x001C002C, 0x00322E10, 0x00310430, 0x00306E30, 0x00050505}, 3094 | [BYOND_VERSION_ADJUSTED(1644)] = {0x00786DF0, 0x00786DEC, 0x00786DD8, 0x00786DD4, 0x00786D80, 0x00786D7C, 0x001C002C, 0x003486D0, 0x00334490, 0x00322C90, 0x00050505}, 3095 | [BYOND_VERSION_ADJUSTED(1645)] = {0x00788DF0, 0x00788DEC, 0x00788DD8, 0x00788DD4, 0x00788D80, 0x00788D7C, 0x001C002C, 0x0034A240, 0x00336000, 0x00324800, 0x00050505}, 3096 | [BYOND_VERSION_ADJUSTED(1646)] = {0x00788DF0, 0x00788DEC, 0x00788DD8, 0x00788DD4, 0x00788D80, 0x00788D7C, 0x001C002C, 0x0034A430, 0x003361F0, 0x003249F0, 0x00050505}, 3097 | [BYOND_VERSION_ADJUSTED(1647)] = {0x00787DF0, 0x00787DEC, 0x00787DD8, 0x00787DD4, 0x00787D98, 0x00787D94, 0x001C002C, 0x00349680, 0x003353D0, 0x00323B20, 0x00050505}, 3098 | }; 3099 | 3100 | #endif 3101 | 3102 | UTRACY_INTERNAL 3103 | void build_srclocs(void) { 3104 | #define byond_get_string(id) ((id) < *byond.strings_len ? *(*byond.strings + (id)) : NULL) 3105 | #define byond_get_misc(id) ((id) < *byond.miscs_len ? *(*byond.miscs + (id)) : NULL) 3106 | #define byond_get_procdef(id) ((id) < *byond.procdefs_len ? (*byond.procdefs) + (id) * byond.procdef_desc.size : NULL) 3107 | #define byond_get_procdef_path(procdef) *((int unsigned *) ((procdef) + byond.procdef_desc.path)) 3108 | #define byond_get_procdef_bytecode(procdef) *((int unsigned *) ((procdef) + byond.procdef_desc.bytecode)) 3109 | 3110 | for(int unsigned i=0; i<0x14000; i++) { 3111 | char *name = NULL; 3112 | char *function = ""; 3113 | char *file = ""; 3114 | int unsigned line = 0xFFFFFFFFu; 3115 | int unsigned color = 0x4444AF; 3116 | 3117 | char *procdef = byond_get_procdef(i); 3118 | if(procdef != NULL) { 3119 | struct string *str = byond_get_string(byond_get_procdef_path(procdef)); 3120 | if(str != NULL && str->data != NULL) { 3121 | function = str->data; 3122 | } 3123 | 3124 | struct misc *misc = byond_get_misc(byond_get_procdef_bytecode(procdef)); 3125 | if(misc != NULL) { 3126 | int unsigned bytecode_len = misc->bytecode.len; 3127 | int unsigned *bytecode = misc->bytecode.bytecode; 3128 | if(bytecode_len >= 2) { 3129 | if(bytecode[0x00] == 0x84) { 3130 | int unsigned file_id = bytecode[0x01]; 3131 | struct string *file_str = byond_get_string(file_id); 3132 | if(file_str != NULL && file_str->data != NULL) { 3133 | file = file_str->data; 3134 | } 3135 | 3136 | if(bytecode_len >= 4) { 3137 | if(bytecode[0x02] == 0x85) { 3138 | line = bytecode[0x03]; 3139 | } 3140 | } 3141 | } 3142 | } 3143 | } 3144 | } 3145 | 3146 | srclocs[i] = (struct utracy_source_location) { 3147 | .name = name, 3148 | .function = function, 3149 | .file = file, 3150 | .line = line, 3151 | .color = color 3152 | }; 3153 | } 3154 | 3155 | #undef byond_get_string 3156 | #undef byond_get_misc 3157 | #undef byond_get_procdef 3158 | #undef byond_get_procdef_path 3159 | #undef byond_get_procdef_bytecode 3160 | } 3161 | 3162 | /* byond api */ 3163 | static int initialized = 0; 3164 | 3165 | UTRACY_EXTERNAL 3166 | char *UTRACY_WINDOWS_CDECL UTRACY_LINUX_CDECL init(int argc, char **argv) { 3167 | (void) argc; 3168 | (void) argv; 3169 | 3170 | if(0 != initialized) { 3171 | return "already initialized"; 3172 | } 3173 | 3174 | (void) UTRACY_MEMSET(&byond, 0, sizeof(byond)); 3175 | (void) UTRACY_MEMSET(&utracy, 0, sizeof(utracy)); 3176 | 3177 | utracy.info.init_begin = utracy_tsc(); 3178 | 3179 | if(0 != event_queue_init()) { 3180 | LOG_DEBUG_ERROR; 3181 | return "event_queue_init failed"; 3182 | } 3183 | 3184 | if(NULL == LZ4_initStream(&utracy.data.stream, sizeof(utracy.data.stream))) { 3185 | LOG_DEBUG_ERROR; 3186 | return "LZ4_initStream failed"; 3187 | } 3188 | 3189 | typedef int (*PFN_GETBYONDBUILD)(void); 3190 | PFN_GETBYONDBUILD GetByondBuild; 3191 | 3192 | #if defined(UTRACY_WINDOWS) 3193 | char *byondcore = (char *) GetModuleHandleA("byondcore.dll"); 3194 | if(NULL == byondcore) { 3195 | LOG_DEBUG_ERROR; 3196 | return "unable to find base address of byondcore.dll"; 3197 | } 3198 | 3199 | GetByondBuild = (PFN_GETBYONDBUILD) GetProcAddress( 3200 | (HMODULE) byondcore, 3201 | "?GetByondBuild@ByondLib@@QAEJXZ" 3202 | ); 3203 | if(NULL == GetByondBuild) { 3204 | LOG_DEBUG_ERROR; 3205 | return "unable to find GetByondBuild"; 3206 | } 3207 | 3208 | #elif defined(UTRACY_LINUX) 3209 | struct link_map *libbyond = dlopen("libbyond.so", (RTLD_NOW | RTLD_NOLOAD)); 3210 | if(NULL == libbyond) { 3211 | LOG_DEBUG_ERROR; 3212 | return "unable to find base address of libbyond.so"; 3213 | } 3214 | 3215 | GetByondBuild = dlsym(libbyond, "_ZN8ByondLib13GetByondBuildEv"); 3216 | if(NULL == GetByondBuild) { 3217 | LOG_DEBUG_ERROR; 3218 | return "unable to find GetByondBuild"; 3219 | } 3220 | 3221 | #endif 3222 | 3223 | int byond_build = GetByondBuild(); 3224 | if(byond_build < BYOND_MIN_BUILD || byond_build > BYOND_MAX_BUILD) { 3225 | LOG_DEBUG_ERROR; 3226 | return "byond version unsupported"; 3227 | } 3228 | 3229 | int unsigned const *const offsets = byond_offsets[BYOND_VERSION_ADJUSTED(byond_build)]; 3230 | 3231 | for(int i=0; i<11; i++) { 3232 | if(offsets[i] == 0) { 3233 | LOG_DEBUG_ERROR; 3234 | return "byond version unsupported"; 3235 | } 3236 | } 3237 | 3238 | char unsigned prologues[3]; 3239 | 3240 | #if defined(UTRACY_WINDOWS) 3241 | byond.strings = (void *) (byondcore + offsets[0]); 3242 | byond.strings_len = (void *) (byondcore + offsets[1]); 3243 | byond.miscs = (void *) (byondcore + offsets[2]); 3244 | byond.miscs_len = (void *) (byondcore + offsets[3]); 3245 | byond.procdefs = (void *) (byondcore + offsets[4]); 3246 | byond.procdefs_len = (void *) (byondcore + offsets[5]); 3247 | byond.procdef_desc.size = (offsets[6] >> 0) & 0xFF; 3248 | byond.procdef_desc.path = (offsets[6] >> 8) & 0xFF; 3249 | byond.procdef_desc.bytecode = (offsets[6] >> 16) & 0xFF; 3250 | byond.exec_proc = (void *) (byondcore + offsets[7]); 3251 | byond.server_tick = (void *) (byondcore + offsets[8]); 3252 | byond.send_maps = (void *) (byondcore + offsets[9]); 3253 | prologues[0] = (offsets[10] >> 0) & 0xFF; 3254 | prologues[1] = (offsets[10] >> 8) & 0xFF; 3255 | prologues[2] = (offsets[10] >> 16) & 0xFF; 3256 | 3257 | #elif defined(UTRACY_LINUX) 3258 | byond.strings = (void *) (libbyond->l_addr + offsets[0]); 3259 | byond.strings_len = (void *) (libbyond->l_addr + offsets[1]); 3260 | byond.miscs = (void *) (libbyond->l_addr + offsets[2]); 3261 | byond.miscs_len = (void *) (libbyond->l_addr + offsets[3]); 3262 | byond.procdefs = (void *) (libbyond->l_addr + offsets[4]); 3263 | byond.procdefs_len = (void *) (libbyond->l_addr + offsets[5]); 3264 | byond.procdef_desc.size = (offsets[6] >> 0) & 0xFF; 3265 | byond.procdef_desc.path = (offsets[6] >> 8) & 0xFF; 3266 | byond.procdef_desc.bytecode = (offsets[6] >> 16) & 0xFF; 3267 | byond.exec_proc = (void *) (libbyond->l_addr + offsets[7]); 3268 | byond.server_tick = (void *) (libbyond->l_addr + offsets[8]); 3269 | byond.send_maps = (void *) (libbyond->l_addr + offsets[9]); 3270 | prologues[0] = (offsets[10] >> 0) & 0xFF; 3271 | prologues[1] = (offsets[10] >> 8) & 0xFF; 3272 | prologues[2] = (offsets[10] >> 16) & 0xFF; 3273 | 3274 | #endif 3275 | 3276 | LOG_INFO("byond build = %d\n", byond_build); 3277 | 3278 | byond.orig_exec_proc = hook((void *) exec_proc, byond.exec_proc, prologues[0], byond.trampoline.exec_proc); 3279 | if(NULL == byond.orig_exec_proc) { 3280 | LOG_DEBUG_ERROR; 3281 | return "failed to hook exec_proc"; 3282 | } 3283 | 3284 | byond.orig_server_tick = hook((void *) server_tick, byond.server_tick, prologues[1], byond.trampoline.server_tick); 3285 | if(NULL == byond.orig_server_tick) { 3286 | LOG_DEBUG_ERROR; 3287 | return "failed to hook server_tick"; 3288 | } 3289 | 3290 | byond.orig_send_maps = hook((void *) send_maps, byond.send_maps, prologues[2], byond.trampoline.send_maps); 3291 | if(NULL == byond.orig_send_maps) { 3292 | LOG_DEBUG_ERROR; 3293 | return "failed to hook send_maps"; 3294 | } 3295 | 3296 | #if defined(UTRACY_WINDOWS) 3297 | DWORD old_protect; 3298 | if(0 == VirtualProtect(&byond.trampoline, UTRACY_PAGE_SIZE, PAGE_EXECUTE_READ, &old_protect)) { 3299 | LOG_DEBUG_ERROR; 3300 | return "failed to set trampoline access protection"; 3301 | } 3302 | 3303 | #elif defined(UTRACY_LINUX) 3304 | if(0 != mprotect(&byond.trampoline, UTRACY_PAGE_SIZE, PROT_READ | PROT_EXEC)) { 3305 | LOG_DEBUG_ERROR; 3306 | return "failed to set trampoline access protection"; 3307 | } 3308 | 3309 | #endif 3310 | 3311 | build_srclocs(); 3312 | 3313 | #if defined(UTRACY_LINUX) 3314 | linux_main_tid = syscall(__NR_gettid); 3315 | #endif 3316 | 3317 | if(0 != utracy_server_init()) { 3318 | return "failed to init server"; 3319 | } 3320 | 3321 | utracy.info.resolution = calibrate_resolution(); 3322 | utracy.info.delay = calibrate_delay(); 3323 | utracy.info.multiplier = calibrate_multiplier(); 3324 | utracy.info.epoch = unix_timestamp(); 3325 | utracy.info.exec_time = unix_timestamp(); 3326 | utracy.info.init_end = utracy_tsc(); 3327 | 3328 | #if defined(UTRACY_WINDOWS) 3329 | if(NULL == CreateThread(NULL, 0, utracy_server_thread_start, NULL, 0, NULL)) { 3330 | LOG_DEBUG_ERROR; 3331 | return "CreateThread failed"; 3332 | } 3333 | 3334 | #elif defined(UTRACY_LINUX) 3335 | pthread_t thr; 3336 | if(0 != pthread_create(&thr, NULL, utracy_server_thread_start, NULL)) { 3337 | LOG_DEBUG_ERROR; 3338 | return "pthread_create failed"; 3339 | } 3340 | 3341 | #endif 3342 | 3343 | initialized = 1; 3344 | return "0"; 3345 | } 3346 | 3347 | UTRACY_EXTERNAL 3348 | char *UTRACY_WINDOWS_CDECL UTRACY_LINUX_CDECL destroy(int argc, char **argv) { 3349 | (void) argc; 3350 | (void) argv; 3351 | 3352 | /* not yet implemented */ 3353 | 3354 | return "0"; 3355 | } 3356 | 3357 | #if (__STDC_HOSTED__ == 0) && defined(UTRACY_WINDOWS) 3358 | BOOL WINAPI DllMainCRTStartup(HINSTANCE instance, DWORD reason, LPVOID reserved) { 3359 | return TRUE; 3360 | } 3361 | #endif 3362 | --------------------------------------------------------------------------------