Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
9a56a4c
LATX, refactor: add KZT guest object registry
LaurenIsACoder Jun 29, 2026
12af38b
LATX, refactor: add KZT guest link map reader
LaurenIsACoder Jun 30, 2026
7ba2852
LATX, refactor: add KZT observation adapter
LaurenIsACoder Jun 30, 2026
07f6cb7
LATX, refactor: route KZT callback through registry adapter
LaurenIsACoder Jun 30, 2026
dda9427
LATX, refactor: add KZT guest registry diagnostics
LaurenIsACoder Jun 30, 2026
621c7e1
LATX, test: cover KZT guest registry concurrency
LaurenIsACoder Jun 30, 2026
60dfbf1
LATX, refactor: wire KZT registry diagnostics logging
LaurenIsACoder Jun 30, 2026
ceddda0
LATX, refactor: add KZT registry diagnostics option
LaurenIsACoder Jun 30, 2026
51d37d0
LATX, fix: gate KZT registry diagnostics output
LaurenIsACoder Jun 30, 2026
7f33d0a
LATX, doc: describe KZT registry diagnostics option
LaurenIsACoder Jun 30, 2026
312b76f
LATX, test: cover KZT registry diagnostics gate
LaurenIsACoder Jul 1, 2026
a86e45a
CI, fix: lowercase GHCR image owner
LaurenIsACoder Jul 1, 2026
7a52689
LATX, refactor: add KZT guest dynamic parser
LaurenIsACoder Jul 6, 2026
125277a
LATX, refactor: report KZT dynamic parser edges
LaurenIsACoder Jul 6, 2026
4f22a8d
LATX, refactor: store KZT guest dynamic snapshots
LaurenIsACoder Jul 6, 2026
75ad9a3
LATX, refactor: commit KZT dynamic views from adapter
LaurenIsACoder Jul 7, 2026
191c58c
LATX, refactor: add KZT dynamic diagnostics helper
LaurenIsACoder Jul 7, 2026
b6af8a3
LATX, refactor: summarize KZT dynamic comparisons
LaurenIsACoder Jul 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions .github/workflows/build-docker-images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,16 @@ jobs:
with:
persist-credentials: false

- name: Pull existing image
run: docker pull ghcr.io/${{ github.repository_owner }}/${{ matrix.IMAGE.TAG_NAME }} || true
if: github.event_name != 'schedule' && github.event_name != 'workflow_dispatch'

- name: Get image name
id: image-name
run: |
ATTEST_IMAGE=$(echo "${{ matrix.IMAGE.TAG_NAME }}" | cut -d ':' -f 1)
echo "ATTEST_IMAGE=${ATTEST_IMAGE}" | tee -a "$GITHUB_OUTPUT"
echo "GHCR_OWNER=${GITHUB_REPOSITORY_OWNER,,}" | tee -a "$GITHUB_OUTPUT"

- name: Pull existing image
run: docker pull "ghcr.io/${{ steps.image-name.outputs.GHCR_OWNER }}/${{ matrix.IMAGE.TAG_NAME }}" || true
if: github.event_name != 'schedule' && github.event_name != 'workflow_dispatch'

- name: Setup QEMU
uses: docker/setup-qemu-action@v4
Expand All @@ -70,15 +71,15 @@ jobs:
id: docker-build
with:
context: ${{ matrix.IMAGE.DOCKERFILE_PATH }}
cache-from: ghcr.io/${{ github.repository_owner }}/${{ matrix.IMAGE.TAG_NAME }}
tags: ghcr.io/${{ github.repository_owner }}/${{ matrix.IMAGE.TAG_NAME }}
cache-from: ghcr.io/${{ steps.image-name.outputs.GHCR_OWNER }}/${{ matrix.IMAGE.TAG_NAME }}
tags: ghcr.io/${{ steps.image-name.outputs.GHCR_OWNER }}/${{ matrix.IMAGE.TAG_NAME }}
platforms: ${{ matrix.IMAGE.DOCKER_PLATFORM }}
pull: true
push: ${{ (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/master' }}

- uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-name: "ghcr.io/${{ github.repository_owner }}/${{ steps.image-name.outputs.ATTEST_IMAGE }}"
subject-name: "ghcr.io/${{ steps.image-name.outputs.GHCR_OWNER }}/${{ steps.image-name.outputs.ATTEST_IMAGE }}"
subject-digest: ${{ steps.docker-build.outputs.digest }}
push-to-registry: true
if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/master'
3 changes: 2 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ jobs:

- name: "Build LATX"
run: |
DOCKER_IMAGE="ghcr.io/${{ github.repository_owner }}/${{ matrix.container }}:loong64"
GHCR_OWNER="${GITHUB_REPOSITORY_OWNER,,}"
DOCKER_IMAGE="ghcr.io/${GHCR_OWNER}/${{ matrix.container }}:loong64"
DOCKER_CMD="./latxbuild/${{ matrix.type }}.sh -c"
docker run --rm \
--platform linux/loong64 \
Expand Down
6 changes: 6 additions & 0 deletions docs/user/latx-environment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ AOT(预翻译)会保存恢复预翻译信息,某些配置与 AOT 冲突,
- 库直通
-
-
* - LATX\_KZT\_REGISTRY\_DIAGNOSTICS
- ``-latx-kzt-registry-diagnostics``
- kzt\_registry\_diagnostics
- KZT registry 诊断输出
-
- 仅控制 KZT registry 诊断输出,不单独启用 KZT;通常需配合 ``LATX_KZT=2`` 或 ``-latx-kzt 2``
* - LATX\_FPUTAG
- ``-latx-fputag``
- option\_fputag
Expand Down
9 changes: 9 additions & 0 deletions linux-user/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ int box64_pagesize;
uintptr_t box64_load_addr = 0;
int dlsym_error = 0;
int kzt_call_log = 0;
int kzt_registry_diagnostics = 0;
int cycle_log = 0;
int allow_missing_libs = 1;
int box64_nogtk = 0;
Expand Down Expand Up @@ -635,6 +636,11 @@ static void handle_arg_latx_kzt(const char *arg)
{
option_kzt = strtol(arg, NULL, 0);
}

static void handle_arg_latx_kzt_registry_diagnostics(const char *arg)
{
kzt_registry_diagnostics = strtol(arg, NULL, 0);
}
#endif

static void handle_arg_latx_fputag(const char *arg)
Expand Down Expand Up @@ -818,6 +824,9 @@ static const struct qemu_argument arg_table[] = {
#if defined(CONFIG_LATX_KZT)
{"latx-kzt", "LATX_KZT", true, handle_arg_latx_kzt,
"", "enable kuzhitong"},
{"latx-kzt-registry-diagnostics", "LATX_KZT_REGISTRY_DIAGNOSTICS",
true, handle_arg_latx_kzt_registry_diagnostics,
"", "enable KZT guest registry diagnostics"},
#endif
{"latx-fputag", "LATX_FPUTAG", true, handle_arg_latx_fputag,
"", "enable fputag"},
Expand Down
20 changes: 20 additions & 0 deletions target/i386/latx/context/box64context.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#include "librarian.h"
#include "library.h"
#include "wrapper.h"
#ifdef CONFIG_LATX_KZT
#include "kzt_guest_registry.h"
#endif
#include <pthread.h>

box64context_t *NewBox64Context(int argc)
Expand All @@ -34,6 +37,19 @@ box64context_t *NewBox64Context(int argc)
return context;
}

#ifdef CONFIG_LATX_KZT
kzt_guest_registry_t *KztGuestRegistryForContext(box64context_t *context)
{
if (!context) {
return NULL;
}
if (!context->kzt_guest_registry) {
context->kzt_guest_registry = kzt_guest_registry_init();
}
return context->kzt_guest_registry;
}
#endif

EXPORTDYN
void FreeBox64Context(box64context_t** context)
{
Expand All @@ -45,6 +61,10 @@ void FreeBox64Context(box64context_t** context)

box64context_t* ctx = *context; // local copy to do the cleanning

#ifdef CONFIG_LATX_KZT
kzt_guest_registry_destroy(&ctx->kzt_guest_registry);
#endif

if(ctx->local_maplib)
FreeLibrarian(&ctx->local_maplib);
if(ctx->maplib)
Expand Down
265 changes: 265 additions & 0 deletions target/i386/latx/context/kzt_guest_dynamic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
#include "kzt_guest_dynamic.h"

#include <string.h>

static void kzt_guest_dynamic_field_set(
kzt_guest_dynamic_field_t *field,
uint64_t value,
kzt_guest_dynamic_address_semantics_t semantics)
{
field->present = 1;
field->value = value;
field->address_semantics = semantics;
}

static int kzt_guest_dynamic_read_entry(
uintptr_t dynamic_addr,
size_t index,
const kzt_guest_link_map_reader_ops_t *reader_ops,
Elf64_Dyn *entry,
uintptr_t *entry_addr)
{
uintptr_t offset;

if (index > UINTPTR_MAX / sizeof(*entry)) {
return -1;
}

offset = index * sizeof(*entry);
if (dynamic_addr > UINTPTR_MAX - offset) {
return -1;
}

*entry_addr = dynamic_addr + offset;
return reader_ops->read_memory(*entry_addr, entry, sizeof(*entry),
reader_ops->opaque) == 0 ? 0 : -1;
}

static int kzt_guest_dynamic_add_needed(kzt_guest_dynamic_view_t *view,
uint64_t offset)
{
size_t new_count = view->needed_count + 1;

if (new_count < view->needed_count ||
new_count > KZT_GUEST_DYNAMIC_NEEDED_LIMIT) {
return -1;
}

view->needed_offsets[view->needed_count] = offset;
view->needed_count = new_count;
view->needed_address_semantics = KZT_GUEST_DYNAMIC_STRING_TABLE_OFFSET;
return 0;
}

static void kzt_guest_dynamic_record_unknown_tag(
kzt_guest_dynamic_view_t *view,
int64_t tag,
size_t index)
{
if (view->unknown_tag_count == 0) {
view->first_unknown_tag = tag;
view->first_unknown_tag_index = index;
}
++view->unknown_tag_count;
}

static int kzt_guest_dynamic_record_entry(kzt_guest_dynamic_view_t *view,
const Elf64_Dyn *entry,
size_t index)
{
uint64_t value = entry->d_un.d_val;
uint64_t ptr = entry->d_un.d_ptr;

switch (entry->d_tag) {
case DT_NEEDED:
return kzt_guest_dynamic_add_needed(view, value);
case DT_SYMTAB:
kzt_guest_dynamic_field_set(&view->symtab, ptr,
KZT_GUEST_DYNAMIC_RUNTIME_ADDRESS);
break;
case DT_STRTAB:
kzt_guest_dynamic_field_set(&view->strtab, ptr,
KZT_GUEST_DYNAMIC_RUNTIME_ADDRESS);
break;
case DT_SYMENT:
kzt_guest_dynamic_field_set(&view->syment, value,
KZT_GUEST_DYNAMIC_SCALAR);
break;
case DT_STRSZ:
kzt_guest_dynamic_field_set(&view->strsz, value,
KZT_GUEST_DYNAMIC_SCALAR);
break;
case DT_HASH:
kzt_guest_dynamic_field_set(&view->hash, ptr,
KZT_GUEST_DYNAMIC_RUNTIME_ADDRESS);
break;
case DT_GNU_HASH:
kzt_guest_dynamic_field_set(&view->gnu_hash, ptr,
KZT_GUEST_DYNAMIC_RUNTIME_ADDRESS);
break;
case DT_VERSYM:
kzt_guest_dynamic_field_set(&view->versym, ptr,
KZT_GUEST_DYNAMIC_RUNTIME_ADDRESS);
break;
case DT_VERNEED:
kzt_guest_dynamic_field_set(&view->verneed, ptr,
KZT_GUEST_DYNAMIC_RUNTIME_ADDRESS);
break;
case DT_VERNEEDNUM:
kzt_guest_dynamic_field_set(&view->verneednum, value,
KZT_GUEST_DYNAMIC_SCALAR);
break;
case DT_VERDEF:
kzt_guest_dynamic_field_set(&view->verdef, ptr,
KZT_GUEST_DYNAMIC_RUNTIME_ADDRESS);
break;
case DT_VERDEFNUM:
kzt_guest_dynamic_field_set(&view->verdefnum, value,
KZT_GUEST_DYNAMIC_SCALAR);
break;
case DT_RELA:
kzt_guest_dynamic_field_set(&view->rela, ptr,
KZT_GUEST_DYNAMIC_RUNTIME_ADDRESS);
break;
case DT_RELASZ:
kzt_guest_dynamic_field_set(&view->relasz, value,
KZT_GUEST_DYNAMIC_SCALAR);
break;
case DT_RELAENT:
kzt_guest_dynamic_field_set(&view->relaent, value,
KZT_GUEST_DYNAMIC_SCALAR);
break;
case DT_REL:
kzt_guest_dynamic_field_set(&view->rel, ptr,
KZT_GUEST_DYNAMIC_RUNTIME_ADDRESS);
break;
case DT_RELSZ:
kzt_guest_dynamic_field_set(&view->relsz, value,
KZT_GUEST_DYNAMIC_SCALAR);
break;
case DT_RELENT:
kzt_guest_dynamic_field_set(&view->relent, value,
KZT_GUEST_DYNAMIC_SCALAR);
break;
case DT_JMPREL:
kzt_guest_dynamic_field_set(&view->jmprel, ptr,
KZT_GUEST_DYNAMIC_RUNTIME_ADDRESS);
break;
case DT_PLTRELSZ:
kzt_guest_dynamic_field_set(&view->pltrelsz, value,
KZT_GUEST_DYNAMIC_SCALAR);
break;
case DT_PLTREL:
kzt_guest_dynamic_field_set(&view->pltrel, value,
KZT_GUEST_DYNAMIC_SCALAR);
break;
case DT_PLTGOT:
kzt_guest_dynamic_field_set(&view->pltgot, ptr,
KZT_GUEST_DYNAMIC_RUNTIME_ADDRESS);
break;
default:
kzt_guest_dynamic_record_unknown_tag(view, entry->d_tag, index);
break;
}

return 0;
}

static void kzt_guest_dynamic_publish_view(
kzt_guest_dynamic_parse_result_t *result,
const kzt_guest_dynamic_view_t *view)
{
result->status = view->status;
result->entry_count = view->entry_count;
result->scan_limit = view->scan_limit;
result->unknown_tag_count = view->unknown_tag_count;
result->first_unknown_tag = view->first_unknown_tag;
result->first_unknown_tag_index = view->first_unknown_tag_index;
result->view = *view;
}

int kzt_guest_dynamic_parse(
uintptr_t dynamic_addr,
uintptr_t load_bias,
const kzt_guest_link_map_reader_ops_t *reader_ops,
kzt_guest_dynamic_parse_result_t *result)
{
kzt_guest_dynamic_view_t view;
size_t i;

if (!result) {
return -1;
}

memset(result, 0, sizeof(*result));
result->status = KZT_GUEST_DYNAMIC_ERROR;
result->error = KZT_GUEST_DYNAMIC_ERROR_INVALID_ARGUMENT;

if (!dynamic_addr || !reader_ops || !reader_ops->read_memory) {
return -1;
}

memset(&view, 0, sizeof(view));
view.dynamic_addr = dynamic_addr;
view.load_bias = load_bias;
view.scan_limit = KZT_GUEST_DYNAMIC_SCAN_LIMIT;

for (i = 0; i < KZT_GUEST_DYNAMIC_SCAN_LIMIT; ++i) {
Elf64_Dyn entry;
uintptr_t entry_addr = 0;

if (kzt_guest_dynamic_read_entry(dynamic_addr, i, reader_ops,
&entry, &entry_addr) != 0) {
view.status = KZT_GUEST_DYNAMIC_READ_ERROR;
view.entry_count = i;
result->read_error_addr = entry_addr;
result->error = KZT_GUEST_DYNAMIC_ERROR_READ_FAILURE;
kzt_guest_dynamic_publish_view(result, &view);
return 0;
}

if (entry.d_tag == DT_NULL) {
view.status = KZT_GUEST_DYNAMIC_COMPLETE;
view.entry_count = i;
view.has_null = 1;
result->error = KZT_GUEST_DYNAMIC_ERROR_NONE;
kzt_guest_dynamic_publish_view(result, &view);
return 0;
}

if (kzt_guest_dynamic_record_entry(&view, &entry, i) != 0) {
view.status = KZT_GUEST_DYNAMIC_ERROR;
view.entry_count = i;
result->status = KZT_GUEST_DYNAMIC_ERROR;
result->error = KZT_GUEST_DYNAMIC_ERROR_TOO_MANY_NEEDED;
kzt_guest_dynamic_publish_view(result, &view);
return 0;
}
}

view.status = KZT_GUEST_DYNAMIC_TRUNCATED_NO_NULL;
view.entry_count = KZT_GUEST_DYNAMIC_SCAN_LIMIT;
result->error = KZT_GUEST_DYNAMIC_ERROR_SCAN_LIMIT_EXCEEDED;
kzt_guest_dynamic_publish_view(result, &view);
return 0;
}

void kzt_guest_dynamic_view_destroy(kzt_guest_dynamic_view_t *view)
{
if (!view) {
return;
}

memset(view, 0, sizeof(*view));
}

void kzt_guest_dynamic_parse_result_clear(
kzt_guest_dynamic_parse_result_t *result)
{
if (!result) {
return;
}

kzt_guest_dynamic_view_destroy(&result->view);
memset(result, 0, sizeof(*result));
}
Loading
Loading