drgn/libdrgn/path.c
Omar Sandoval 87b7292aa5 Relicense drgn from GPLv3+ to LGPLv2.1+
drgn is currently licensed as GPLv3+. Part of the long term vision for
drgn is that other projects can use it as a library providing
programmatic interfaces for debugger functionality. A more permissive
license is better suited to this goal. We decided on LGPLv2.1+ as a good
balance between software freedom and permissiveness.

All contributors not employed by Meta were contacted via email and
consented to the license change. The only exception was the author of
commit c4fbf7e589 ("libdrgn: fix for compilation error"), who did not
respond. That commit reverted a single line of code to one originally
written by me in commit 640b1c011d ("libdrgn: embed DWARF index in
DWARF info cache").

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2022-11-01 17:05:16 -07:00

154 lines
3.8 KiB
C

// Copyright (c) Meta Platforms, Inc. and affiliates.
// SPDX-License-Identifier: LGPL-2.1-or-later
#include <stdbool.h>
#include <string.h>
#include "drgn.h"
#include "dwarf_constants.h"
#include "path.h"
#include "util.h"
bool path_iterator_next(struct path_iterator *it, const char **component_ret,
size_t *component_len_ret)
{
while (it->num_components) {
struct nstring *cur = &it->components[it->num_components - 1];
while (cur->len > 0) {
if (cur->str[cur->len - 1] == '/') {
if (cur->len == 1) {
/*
* This is an absolute path. Emit an
* empty component. Components joined
* before this one and remaining ".."
* components are not meaningful.
*/
it->num_components = 0;
it->dot_dot = 0;
*component_ret = "";
*component_len_ret = 0;
return true;
}
/* Skip redundant slashes. */
cur->len--;
continue;
}
size_t component_start = cur->len - 1;
while (component_start > 0 &&
cur->str[component_start - 1] != '/')
component_start--;
size_t component_len = cur->len - component_start;
cur->len = component_start;
if (component_len == 1 &&
cur->str[component_start] == '.') {
/* Skip "." components. */
} else if (component_len == 2 &&
cur->str[component_start] == '.' &&
cur->str[component_start + 1] == '.') {
/* Count ".." components. */
it->dot_dot++;
} else if (it->dot_dot) {
it->dot_dot--;
} else {
*component_ret = &cur->str[component_start];
*component_len_ret = component_len;
return true;
}
}
it->num_components--;
}
if (it->dot_dot) {
/*
* Leftover ".." components must be above the current
* directory.
*/
it->dot_dot--;
*component_ret = "..";
*component_len_ret = 2;
return true;
}
return false;
}
bool path_ends_with(struct path_iterator *haystack,
struct path_iterator *needle)
{
for (;;) {
const char *h_component, *n_component;
size_t h_component_len, n_component_len;
if (!path_iterator_next(needle, &n_component, &n_component_len))
return true;
if (!path_iterator_next(haystack, &h_component,
&h_component_len))
return false;
if (h_component_len != n_component_len ||
memcmp(h_component, n_component, h_component_len) != 0)
return false;
}
}
bool die_matches_filename(Dwarf_Die *die, const char *filename)
{
if (!filename || !filename[0])
return true;
struct nstring die_components[2];
struct path_iterator die_path = {
.components = die_components,
};
Dwarf_Die cu_die;
Dwarf_Attribute attr_mem, *attr;
attr = dwarf_attr_integrate(dwarf_diecu(die, &cu_die, NULL, NULL),
DW_AT_comp_dir, &attr_mem);
const char *path = dwarf_formstring(attr);
if (path) {
die_path.components[die_path.num_components].str = path;
die_path.components[die_path.num_components].len = strlen(path);
die_path.num_components++;
}
path = dwarf_decl_file(die);
if (!path)
return false;
/*
* If the declaration file name is absolute, the compilation directory
* component will be ignored.
*/
die_path.components[die_path.num_components].str = path;
die_path.components[die_path.num_components].len = strlen(path);
die_path.num_components++;
struct path_iterator needle = {
.components = (struct nstring []){
{ filename, strlen(filename) }
},
.num_components = 1,
};
return path_ends_with(&die_path, &needle);
}
LIBDRGN_PUBLIC bool drgn_filename_matches(const char *haystack,
const char *needle)
{
struct path_iterator haystack_path = {
.components = (struct nstring []){
{ haystack, strlen(haystack) }
},
.num_components = 1,
};
struct path_iterator needle_path = {
.components = (struct nstring []){
{ needle, strlen(needle) }
},
.num_components = 1,
};
return path_ends_with(&haystack_path, &needle_path);
}