How to check if two functions belong to the same class?

Hi, I’m new to LLVM and try to get help here. I would like to write a LLVM pass to do some analysis, but not sure if I can get the information that the class a function belongs to. For example:

#include <cstdio>

class Animal {
    public:
    int id;
    int report_id() {
        return id;
    }
    void change_id(int m) {
        id = m;
    }
    Animal(int x) {
        id = x;
    }
};

int main() {
    Animal* a = new Animal(653);
    int w = a->report_id();
    printf("%d\n", w);
    a->change_id(322);
    w = a->report_id();
    printf("%d\n", w);
    return 0;
}

lowers to LLVM IR:

define dso_local i32 @main() #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) !dbg !206 {
  %1 = alloca i32, align 4
  %2 = alloca %class.Animal*, align 8
  %3 = alloca i8*, align 8
  %4 = alloca i32, align 4
  %5 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  call void @llvm.dbg.declare(metadata %class.Animal** %2, metadata !207, metadata !DIExpression()), !dbg !220
  %6 = call noalias nonnull i8* @_Znwm(i64 4) #7, !dbg !221, !heapallocsite !209
  %7 = bitcast i8* %6 to %class.Animal*, !dbg !221
  invoke void @_ZN6AnimalC2Ei(%class.Animal* nonnull dereferenceable(4) %7, i32 653)
          to label %8 unwind label %18, !dbg !222

8:                                                ; preds = %0
  store %class.Animal* %7, %class.Animal** %2, align 8, !dbg !220
  call void @llvm.dbg.declare(metadata i32* %5, metadata !223, metadata !DIExpression()), !dbg !224
  %9 = load %class.Animal*, %class.Animal** %2, align 8, !dbg !225
  %10 = call i32 @_ZN6Animal9report_idEv(%class.Animal* nonnull dereferenceable(4) %9), !dbg !226
  store i32 %10, i32* %5, align 4, !dbg !224
  %11 = load i32, i32* %5, align 4, !dbg !227
  %12 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32 %11), !dbg !228
  %13 = load %class.Animal*, %class.Animal** %2, align 8, !dbg !229
  call void @_ZN6Animal9change_idEi(%class.Animal* nonnull dereferenceable(4) %13, i32 322), !dbg !230
  %14 = load %class.Animal*, %class.Animal** %2, align 8, !dbg !231
  %15 = call i32 @_ZN6Animal9report_idEv(%class.Animal* nonnull dereferenceable(4) %14), !dbg !232
  store i32 %15, i32* %5, align 4, !dbg !233
  %16 = load i32, i32* %5, align 4, !dbg !234
  %17 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i32 %16), !dbg !235
  ret i32 0, !dbg !236

18:                                               ; preds = %0
  %19 = landingpad { i8*, i32 }
          cleanup, !dbg !237
  %20 = extractvalue { i8*, i32 } %19, 0, !dbg !237
  store i8* %20, i8** %3, align 8, !dbg !237
  %21 = extractvalue { i8*, i32 } %19, 1, !dbg !237
  store i32 %21, i32* %4, align 4, !dbg !237
  call void @_ZdlPv(i8* %6) #8, !dbg !221
  br label %22, !dbg !221

22:                                               ; preds = %18
  %23 = load i8*, i8** %3, align 8, !dbg !221
  %24 = load i32, i32* %4, align 4, !dbg !221
  %25 = insertvalue { i8*, i32 } undef, i8* %23, 0, !dbg !221
  %26 = insertvalue { i8*, i32 } %25, i32 %24, 1, !dbg !221
  resume { i8*, i32 } %26, !dbg !221
}

declare void @llvm.dbg.declare(metadata, metadata, metadata) #1

declare dso_local nonnull i8* @_Znwm(i64) #2

define linkonce_odr dso_local void @_ZN6AnimalC2Ei(%class.Animal* nonnull dereferenceable(4) %0, i32 %1) unnamed_addr #3 comdat align 2 !dbg !238 {
  %3 = alloca %class.Animal*, align 8
  %4 = alloca i32, align 4
  store %class.Animal* %0, %class.Animal** %3, align 8
  call void @llvm.dbg.declare(metadata %class.Animal** %3, metadata !239, metadata !DIExpression()), !dbg !240
  store i32 %1, i32* %4, align 4
  call void @llvm.dbg.declare(metadata i32* %4, metadata !241, metadata !DIExpression()), !dbg !242
  %5 = load %class.Animal*, %class.Animal** %3, align 8
  %6 = load i32, i32* %4, align 4, !dbg !243
  %7 = getelementptr inbounds %class.Animal, %class.Animal* %5, i32 0, i32 0, !dbg !245
  store i32 %6, i32* %7, align 4, !dbg !246
  ret void, !dbg !247
}

declare dso_local i32 @__gxx_personality_v0(...)

declare dso_local void @_ZdlPv(i8*) #4

define linkonce_odr dso_local i32 @_ZN6Animal9report_idEv(%class.Animal* nonnull dereferenceable(4) %0) #5 comdat align 2 !dbg !248 {
  %2 = alloca %class.Animal*, align 8
  store %class.Animal* %0, %class.Animal** %2, align 8
  call void @llvm.dbg.declare(metadata %class.Animal** %2, metadata !249, metadata !DIExpression()), !dbg !250
  %3 = load %class.Animal*, %class.Animal** %2, align 8
  %4 = getelementptr inbounds %class.Animal, %class.Animal* %3, i32 0, i32 0, !dbg !251
  %5 = load i32, i32* %4, align 4, !dbg !251
  ret i32 %5, !dbg !252
}

declare dso_local i32 @printf(i8*, ...) #6

define linkonce_odr dso_local void @_ZN6Animal9change_idEi(%class.Animal* nonnull dereferenceable(4) %0, i32 %1) #5 comdat align 2 !dbg !253 {
  %3 = alloca %class.Animal*, align 8
  %4 = alloca i32, align 4
  store %class.Animal* %0, %class.Animal** %3, align 8
  call void @llvm.dbg.declare(metadata %class.Animal** %3, metadata !254, metadata !DIExpression()), !dbg !255
  store i32 %1, i32* %4, align 4
  call void @llvm.dbg.declare(metadata i32* %4, metadata !256, metadata !DIExpression()), !dbg !257
  %5 = load %class.Animal*, %class.Animal** %3, align 8
  %6 = load i32, i32* %4, align 4, !dbg !258
  %7 = getelementptr inbounds %class.Animal, %class.Animal* %5, i32 0, i32 0, !dbg !259
  store i32 %6, i32* %7, align 4, !dbg !260
  ret void, !dbg !261
}

When the c++ code lowers to LLVM IR, the class information seems to be implicit. Is there a way to know the _ZN6Animal9report_idEv and _ZN6Animal9change_idEi functions belong to the same class Animal? Would the debug info help? Or I should just figure it out based on the function name?

LLVM IR is at a lower level than the C++ abstraction, it is closer to an equivalent C code corresponding to your C++ program. As such there is no notion of class and not generic way of reconstructing this kind of higher level language-specific abstractions.

Thank you for your answer. Is it feasible to reconstruct it through function name?