diff --git a/src/libsysprof-profile/meson.build b/src/libsysprof-profile/meson.build index 36a80eb0..cc0ba551 100644 --- a/src/libsysprof-profile/meson.build +++ b/src/libsysprof-profile/meson.build @@ -17,6 +17,7 @@ libsysprof_profile_public_sources = [ libsysprof_profile_private_sources = [ 'mapped-ring-buffer-source.c', 'sysprof-controlfd-instrument.c', + 'sysprof-maps-parser.c', 'sysprof-perf-event-stream.c', 'sysprof-podman.c', 'sysprof-polkit.c', diff --git a/src/libsysprof-profile/sysprof-maps-parser-private.h b/src/libsysprof-profile/sysprof-maps-parser-private.h new file mode 100644 index 00000000..4fbb373e --- /dev/null +++ b/src/libsysprof-profile/sysprof-maps-parser-private.h @@ -0,0 +1,44 @@ +/* sysprof-maps-parser-private.h + * + * Copyright 2023 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +#include "line-reader-private.h" + +G_BEGIN_DECLS + +typedef struct _SysprofMapsParser +{ + LineReader reader; +} SysprofMapsParser; + +void sysprof_maps_parser_init (SysprofMapsParser *self, + const char *str, + gssize len); +gboolean sysprof_maps_parser_next (SysprofMapsParser *self, + guint64 *out_begin_addr, + guint64 *out_end_addr, + guint64 *out_offset, + guint64 *out_inode, + char **out_filename); + +G_END_DECLS diff --git a/src/libsysprof-profile/sysprof-maps-parser.c b/src/libsysprof-profile/sysprof-maps-parser.c new file mode 100644 index 00000000..200b1f86 --- /dev/null +++ b/src/libsysprof-profile/sysprof-maps-parser.c @@ -0,0 +1,114 @@ +/* sysprof-maps-parser.c + * + * Copyright 2023 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "config.h" + +#include "sysprof-maps-parser-private.h" + +static GRegex *address_range_regex; + +void +sysprof_maps_parser_init (SysprofMapsParser *self, + const char *str, + gssize len) +{ + line_reader_init (&self->reader, (char *)str, len); + + if (address_range_regex == NULL) + address_range_regex = g_regex_new ("^([0-9a-f]+)-([0-9a-f]+) [r\\-][w\\-][x\\-][ps\\-] ([0-9a-f]+) [0-9]{2}:[0-9]{2} ([0-9]+) +(.*)$", + G_REGEX_OPTIMIZE, + G_REGEX_MATCH_DEFAULT, + NULL); +} + +gboolean +sysprof_maps_parser_next (SysprofMapsParser *self, + guint64 *out_begin_addr, + guint64 *out_end_addr, + guint64 *out_offset, + guint64 *out_inode, + char **out_filename) +{ + const char *line; + gsize len; + + while ((line = line_reader_next (&self->reader, &len))) + { + g_autoptr(GMatchInfo) match_info = NULL; + + if (g_regex_match_full (address_range_regex, line, len, 0, 0, &match_info, NULL)) + { + g_autofree char *file = NULL; + guint64 begin_addr; + guint64 end_addr; + guint64 inode; + guint64 offset; + gboolean is_vdso; + int begin_addr_begin; + int begin_addr_end; + int end_addr_begin; + int end_addr_end; + int offset_begin; + int offset_end; + int inode_begin; + int inode_end; + int path_begin; + int path_end; + + + if (!g_match_info_fetch_pos (match_info, 1, &begin_addr_begin, &begin_addr_end) || + !g_match_info_fetch_pos (match_info, 2, &end_addr_begin, &end_addr_end) || + !g_match_info_fetch_pos (match_info, 3, &offset_begin, &offset_end) || + !g_match_info_fetch_pos (match_info, 4, &inode_begin, &inode_end) || + !g_match_info_fetch_pos (match_info, 5, &path_begin, &path_end)) + continue; + + begin_addr = g_ascii_strtoull (&line[begin_addr_begin], NULL, 16); + end_addr = g_ascii_strtoull (&line[end_addr_begin], NULL, 16); + offset = g_ascii_strtoull (&line[offset_begin], NULL, 16); + inode = g_ascii_strtoull (&line[inode_begin], NULL, 10); + + if (memcmp (" (deleted", + &line[path_end] - strlen (" (deleted"), + strlen (" (deleted")) == 0) + path_end -= strlen (" (deleted)"); + + file = g_strndup (&line[path_begin], path_end-path_begin); + + is_vdso = strcmp ("[vdso]", file) == 0; + + if (is_vdso) + inode = 0; + + if (is_vdso) + offset = 0; + + *out_begin_addr = begin_addr; + *out_end_addr = end_addr; + *out_offset = offset; + *out_inode = inode; + *out_filename = g_steal_pointer (&file); + + return TRUE; + } + } + + return FALSE; +} diff --git a/src/libsysprof-profile/tests/meson.build b/src/libsysprof-profile/tests/meson.build index f559ff7e..f6b5d697 100644 --- a/src/libsysprof-profile/tests/meson.build +++ b/src/libsysprof-profile/tests/meson.build @@ -12,6 +12,7 @@ libsysprof_profile_testsuite_c_args = [ ] libsysprof_profile_testsuite = { + 'test-maps-parser' : {'skip': true}, 'test-profiler' : {'skip': true}, } diff --git a/src/libsysprof-profile/tests/test-maps-parser.c b/src/libsysprof-profile/tests/test-maps-parser.c new file mode 100644 index 00000000..6363bb85 --- /dev/null +++ b/src/libsysprof-profile/tests/test-maps-parser.c @@ -0,0 +1,51 @@ +/* test-maps-parser.c + * + * Copyright 2023 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "config.h" + +#include "sysprof-maps-parser-private.h" + +#define ADDR_FORMAT "0x%"G_GINT64_MODIFIER"x" + +int +main (int argc, + char *argv[]) +{ + g_autoptr(GError) error = NULL; + g_autofree char *contents = NULL; + SysprofMapsParser parser; + guint64 begin, end, offset, inode; + char *file; + gsize len; + + g_assert_cmpint (argc, >, 1); + g_file_get_contents (argv[1], &contents, &len, &error); + g_assert_no_error (error); + + sysprof_maps_parser_init (&parser, contents, len); + while (sysprof_maps_parser_next (&parser, &begin, &end, &offset, &inode, &file)) + { + g_print (ADDR_FORMAT" - "ADDR_FORMAT" "ADDR_FORMAT" %"G_GUINT64_FORMAT" %s\n", + begin, end, offset, inode, file); + g_free (file); + } + + return 0; +}